package com.brillilab.service.logic.experiments;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.brillilab.common.alioss.OssFileEnum;
import com.brillilab.common.alioss.OssFileFolderEnum;
import com.brillilab.common.utils.MyBeanUtils;
import com.brillilab.domain.enums.common.BoolEnum;
import com.brillilab.domain.enums.experiment.ExperimentBillSourceEnum;
import com.brillilab.domain.enums.experiment.ExperimentGroupEnum;
import com.brillilab.domain.enums.experiment.ExperimentStateEnum;
import com.brillilab.domain.enums.experiment.ExperimentStepMaterialTypeEnum;
import com.brillilab.domain.enums.experiment.ExperimentStepReagentTypeEnum;
import com.brillilab.domain.enums.experiment.ExperimentStepRelationEnum;
import com.brillilab.domain.enums.experiment.ExperimentStepTextTypeEnum;
import com.brillilab.domain.enums.experiment.ExperimentStepTimerStateEnum;
import com.brillilab.domain.enums.file.FileTypeEnum;
import com.brillilab.domain.enums.inventory.InventoryRecordEnum;
import com.brillilab.domain.enums.kit.KitEnum;
import com.brillilab.domain.enums.kit.KitEnum.Classify;
import com.brillilab.domain.enums.kit.KitUsageEnum;
import com.brillilab.domain.enums.method.MethodSourceEnum;
import com.brillilab.domain.pa.kit.SampleAddPa;
import com.brillilab.domain.pa.kit.SampleAttrPa;
import com.brillilab.domain.po.experiments.Experiment;
import com.brillilab.domain.po.experiments.ExperimentBill;
import com.brillilab.domain.po.experiments.ExperimentComment;
import com.brillilab.domain.po.experiments.ExperimentGroup;
import com.brillilab.domain.po.experiments.ExperimentGroupRelation;
import com.brillilab.domain.po.experiments.ExperimentPhase;
import com.brillilab.domain.po.experiments.ExperimentProduce;
import com.brillilab.domain.po.experiments.ExperimentProduceAttr;
import com.brillilab.domain.po.experiments.ExperimentRelation;
import com.brillilab.domain.po.experiments.ExperimentStep;
import com.brillilab.domain.po.experiments.ExperimentStepReagent;
import com.brillilab.domain.po.experiments.ExperimentStepText;
import com.brillilab.domain.po.experiments.ExperimentStepTimer;
import com.brillilab.domain.po.experiments.ExperimentTroubleShooting;
import com.brillilab.domain.po.experiments.Plate;
import com.brillilab.domain.po.experiments.PlateStepRelate;
import com.brillilab.domain.po.inventory.ReagentInventory;
import com.brillilab.domain.po.kit.Kit;
import com.brillilab.domain.po.kit.KitSpec;
import com.brillilab.domain.po.kit.Reagent;
import com.brillilab.domain.po.kit.ReagentType;
import com.brillilab.domain.po.lab.LabMember;
import com.brillilab.domain.po.method.Method;
import com.brillilab.domain.po.method.MethodPhase;
import com.brillilab.domain.po.method.MethodRelateReagent;
import com.brillilab.domain.po.method.MethodRelateTimer;
import com.brillilab.domain.po.method.MethodStep;
import com.brillilab.domain.po.method.MethodTypeHide;
import com.brillilab.domain.po.system.FileManage;
import com.brillilab.domain.po.topics.Topic;
import com.brillilab.domain.po.topics.TopicExperiment;
import com.brillilab.domain.vo.experiments.AnalyzeDataAddReturnVo;
import com.brillilab.domain.vo.experiments.AnalyzeDataVo;
import com.brillilab.domain.vo.experiments.EvaluationVo;
import com.brillilab.domain.vo.experiments.ExperimentAddVo;
import com.brillilab.domain.vo.experiments.ExperimentCommentAddVo;
import com.brillilab.domain.vo.experiments.ExperimentCommentVo;
import com.brillilab.domain.vo.experiments.ExperimentDtailsVo;
import com.brillilab.domain.vo.experiments.ExperimentGroupListVo;
import com.brillilab.domain.vo.experiments.ExperimentGroupMapVo;
import com.brillilab.domain.vo.experiments.ExperimentGroupRelationIdVo;
import com.brillilab.domain.vo.experiments.ExperimentGroupRelationTreeVo;
import com.brillilab.domain.vo.experiments.ExperimentGroupSaveVo;
import com.brillilab.domain.vo.experiments.ExperimentHeadModifyVo;
import com.brillilab.domain.vo.experiments.ExperimentKitAddListVo;
import com.brillilab.domain.vo.experiments.ExperimentKitAddVo;
import com.brillilab.domain.vo.experiments.ExperimentKitInfoListVo;
import com.brillilab.domain.vo.experiments.ExperimentPhaseProcessVo;
import com.brillilab.domain.vo.experiments.ExperimentPhaseVo;
import com.brillilab.domain.vo.experiments.ExperimentProcessVo;
import com.brillilab.domain.vo.experiments.ExperimentProduceListGroupVo;
import com.brillilab.domain.vo.experiments.ExperimentProduceListGroupVoList;
import com.brillilab.domain.vo.experiments.ExperimentProduceListVo;
import com.brillilab.domain.vo.experiments.ExperimentProduceSaveListVo;
import com.brillilab.domain.vo.experiments.ExperimentProduceSaveVo;
import com.brillilab.domain.vo.experiments.ExperimentReagentVo;
import com.brillilab.domain.vo.experiments.ExperimentRelationListVo;
import com.brillilab.domain.vo.experiments.ExperimentRelationVo;
import com.brillilab.domain.vo.experiments.ExperimentStepModifyVo;
import com.brillilab.domain.vo.experiments.ExperimentStepProcessVo;
import com.brillilab.domain.vo.experiments.ExperimentStepSaveVo;
import com.brillilab.domain.vo.experiments.ExperimentStepSimple;
import com.brillilab.domain.vo.experiments.ExperimentStepVo;
import com.brillilab.domain.vo.experiments.ExperimentTipsVo;
import com.brillilab.domain.vo.experiments.ExperimentTroubleShootingListVo;
import com.brillilab.domain.vo.experiments.ExperimentTroubleShootingMattersVo;
import com.brillilab.domain.vo.experiments.ExperimentTroubleShootingVo;
import com.brillilab.domain.vo.experiments.PrimaryDataAddReturnVo;
import com.brillilab.domain.vo.experiments.PrimaryDataVo;
import com.brillilab.domain.vo.experiments.ReasonAndDealVo;
import com.brillilab.domain.vo.kit.SampleSpecVo;
import com.brillilab.domain.vo.method.MethodDetail;
import com.brillilab.domain.vo.method.MethodPhaseDetail;
import com.brillilab.domain.vo.method.MethodRelateReagentVo;
import com.brillilab.domain.vo.method.MethodStepDetail;
import com.brillilab.domain.vo.method.MethodTypeDetailVo;
import com.brillilab.domain.vo.method.NewMethod;
import com.brillilab.domain.vo.method.NewMethodPhase;
import com.brillilab.domain.vo.method.NewMethodStep;
import com.brillilab.domain.vo.team.TeamMemberVo;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.experiments.IExperimentBillService;
import com.brillilab.service.core.experiments.IExperimentCommentService;
import com.brillilab.service.core.experiments.IExperimentGroupRelationService;
import com.brillilab.service.core.experiments.IExperimentGroupService;
import com.brillilab.service.core.experiments.IExperimentPhaseService;
import com.brillilab.service.core.experiments.IExperimentProduceAttrService;
import com.brillilab.service.core.experiments.IExperimentProduceService;
import com.brillilab.service.core.experiments.IExperimentRelationService;
import com.brillilab.service.core.experiments.IExperimentService;
import com.brillilab.service.core.experiments.IExperimentStepReagentService;
import com.brillilab.service.core.experiments.IExperimentStepService;
import com.brillilab.service.core.experiments.IExperimentStepTextService;
import com.brillilab.service.core.experiments.IExperimentStepTimerService;
import com.brillilab.service.core.experiments.IExperimentTroubleShootingService;
import com.brillilab.service.core.experiments.IPlateGridReagentService;
import com.brillilab.service.core.experiments.IPlateGridTextService;
import com.brillilab.service.core.experiments.IPlateService;
import com.brillilab.service.core.experiments.IPlateStepRelateService;
import com.brillilab.service.core.inventory.IInventoryRecordService;
import com.brillilab.service.core.inventory.IReagentInventoryService;
import com.brillilab.service.core.kit.IKitService;
import com.brillilab.service.core.kit.IKitSpecService;
import com.brillilab.service.core.kit.IKitUsageService;
import com.brillilab.service.core.kit.IReagentService;
import com.brillilab.service.core.kit.IReagentTypeService;
import com.brillilab.service.core.lab.ILabMemberService;
import com.brillilab.service.core.method.IMethodPhaseService;
import com.brillilab.service.core.method.IMethodRelateReagentService;
import com.brillilab.service.core.method.IMethodRelateTimerService;
import com.brillilab.service.core.method.IMethodService;
import com.brillilab.service.core.method.IMethodStepService;
import com.brillilab.service.core.method.IMethodTypeHideService;
import com.brillilab.service.core.method.IMethodTypeService;
import com.brillilab.service.core.plans.IPlanService;
import com.brillilab.service.core.system.IDictService;
import com.brillilab.service.core.system.IFileManageService;
import com.brillilab.service.core.team.ITeamMemberService;
import com.brillilab.service.core.team.ITeamService;
import com.brillilab.service.core.topics.ITopicExperimentService;
import com.brillilab.service.core.topics.ITopicService;
import com.brillilab.service.core.topics.ITopicTargetService;
import com.brillilab.service.core.user.IUsersService;
import com.brillilab.service.logic.comments.CommentsLogic;
import com.brillilab.service.logic.kit.SampleLogic;
import com.brillilab.service.logic.method.MethodLogic;
import com.brillilab.service.logic.team.TeamLogic;
import com.brillilab.service.logic.topics.TopicLogic;
import com.brillilab.service.utils.ReagentUuidsUtil;

import cn.hutool.core.collection.CollUtil;

/**
 * 新实验
 *
 * @author Wu Menghao
 * @time 2019/04/18
 */
@Service
@Transactional
public class ExperimentLogic {
	@Resource
	private IExperimentGroupService experimentGroupService;
	@Resource
	private IExperimentService experimentService;
	@Resource
	private IPlanService planService;
	@Resource
	private ILabMemberService labMemberService;
	@Resource
	private IUsersService usersService;
	@Resource
	private IExperimentTroubleShootingService experimentTroubleShootingService;
	@Resource
	private IFileManageService fileManageService;
	@Resource
	private IReagentInventoryService reagentInventoryService;
	@Resource
	private IDictService dictService;
	@Resource
	private IExperimentCommentService experimentCommentService;
	@Resource
	private IMethodService methodService;
	@Resource
	private IMethodPhaseService methodPhaseService;
	@Resource
	private IMethodStepService methodStepService;
	@Resource
	private IExperimentPhaseService experimentPhaseService;
	@Resource
	private IExperimentStepService experimentStepService;
	@Resource
	private IMethodRelateReagentService methodRelateReagentService;
	@Resource
	private IMethodRelateTimerService methodRelateTimerService;
	@Resource
	private ExperimentStepContentLogic experimentStepContentLogic;
	@Resource
	private IMethodTypeService methodTypeService;
	@Resource
	private ITopicExperimentService topicExperimentService;
	@Resource
	private IReagentTypeService reagentTypeService;
	@Resource
	private IReagentService reagentService;
	@Resource
	private IExperimentStepReagentService experimentStepReagentService;
	@Resource
	private IExperimentStepTimerService experimentStepTimerService;
	@Resource
	private IExperimentBillService experimentBillService;
	@Resource
	private IExperimentProduceService experimentProduceService;
	@Resource
	private IKitService kitService;
	@Resource
	private IKitSpecService kitSpecService;
	@Resource
	private TopicLogic topicLogic;
	@Resource
	private IPlateGridReagentService plateGridReagentService;
	@Resource
	private IExperimentRelationService experimentRelationService;
	@Resource
	private IKitUsageService kitUsageService;
	@Resource
	private IPlateService plateService;
	@Resource
	private IPlateStepRelateService plateStepRelateService;
	@Resource
	private ExperimentStepTimerLogic experimentStepTimerLogic;
	@Resource
	private SampleLogic sampleLogic;
	@Resource
	private IExperimentProduceAttrService experimentProduceAttrService;
	@Resource
	private IInventoryRecordService inventoryRecordService;
	@Resource
	private MethodLogic methodLogic;
	@Resource
	private ITopicService topicService;
	@Resource
	private TeamLogic teamLogic;
	@Resource
	private ITeamMemberService teamMemberService;
	@Resource
	private ITeamService teamService;
	@Resource
	private IMethodTypeHideService methodTypeHideService;
	@Resource
	private IExperimentGroupRelationService experimentGroupRelationService;
	@Resource
	private IExperimentStepTextService experimentStepTextService;
	@Resource
	private IPlateGridTextService plateGridTextService;
	@Resource
	private ITopicTargetService topicTargetService;
	@Resource
	private CommentsLogic commentsLogic;

	// ****** 老逻辑 可用 *******/

	/**
	 * 获取实验步骤详情
	 *
	 * @param userInfo
	 * @param experimentId
	 * @return
	 */
	public ExperimentDtailsVo getExperimentDtails(UserInfoVo userInfo, Long experimentId) {
		ExperimentDtailsVo dtailsVo = new ExperimentDtailsVo();
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验信息不存在");
		// 如果实验阶段步骤已存在就不需要初始化
		List<ExperimentPhase> experimentPhases = experimentPhaseService.selectList(experimentId);
		if (BoolEnum.FALSE.getValue().equals(experiment.getIsImport()) && CollectionUtils.isEmpty(experimentPhases)) {
			this.experimentInfoSave(experiment.getId());
		}
		if (userInfo.getLabMemberId().equals(experiment.getExecutorId())
				&& experiment.getState().equals(ExperimentStateEnum.NOT_STARTED.getValue())) {
			Topic topic = topicService.selectById(experiment.getTopicId());
			LabMember labMember = labMemberService.selectById(topic.getExecutorId());
			MethodTypeHide typeHide = methodTypeHideService.selectMethodTypeHide(labMember.getUserId(),
					experiment.getMethodTypeId());
			if (typeHide == null) {
				List<Method> methodList = methodService
						.getMethodListByUserIdAndState(labMember.getUserId(), BoolEnum.FALSE, BoolEnum.TRUE, false)
						.stream().filter(e -> e.getMethodTypeId().equals(experiment.getMethodTypeId()))
						.collect(Collectors.toList());

				dtailsVo.setHasMethod(
						CollectionUtils.isEmpty(methodList) ? BoolEnum.FALSE.getValue() : BoolEnum.TRUE.getValue());
			}

		}

		dtailsVo.setExperiment(experiment);
		List<ExperimentPhaseVo> phaseList = experimentPhaseService.selectExperimentPhaseVo(experimentId);
		dtailsVo.setPhaseList(phaseList);
//        int clientUserState = this.getClientUserState(labMemberId, dtailsVo.getExperiment());
//        dtailsVo.setClientUserState(clientUserState);
		int nuSendBackNum = kitUsageService.selectExperimentUsageCount(experiment.getLabId(), userInfo.getLabMemberId(),
				experimentId, KitUsageEnum.State.NOT_RETURN.getValue());
		dtailsVo.setNuSendBackNum(nuSendBackNum);
		dtailsVo = this.setRelation(dtailsVo);
		List<Plate> plateList = plateService.getPlateList(experimentId);
		dtailsVo.setIsSavePlate(plateList.size() > 0 ? 1 : 0);
		if (!org.springframework.util.CollectionUtils.isEmpty(phaseList)) {
			phaseFor: for (ExperimentPhaseVo phase : phaseList) {
				if (ExperimentStateEnum.NOT_STARTED.getValue().equals(phase.getState())
						|| ExperimentStateEnum.UNDER_WAY.getValue().equals(phase.getState())) {
					List<ExperimentStepVo> stepList = phase.getExperimentStepVoList();
					if (!org.springframework.util.CollectionUtils.isEmpty(stepList)) {
						for (ExperimentStepVo step : stepList) {
							if (ExperimentStateEnum.NOT_STARTED.getValue().equals(step.getState())
									|| ExperimentStateEnum.UNDER_WAY.getValue().equals(step.getState())) {
								dtailsVo.setUnderWayPhaseId(phase.getPhaseId());
								dtailsVo.setUnderWayStepId(step.getStepId());
								break phaseFor;
							}
						}
					}
				}
			}
		}
		return dtailsVo;
	}

	/**
	 * 关联（多个以英文逗号分隔）：1-tips,2-多孔板,3-试剂,4-定时器,5-仪器,6-产出
	 */
	private ExperimentDtailsVo setRelation(ExperimentDtailsVo dtailsVo) {
		List<ExperimentPhaseVo> phaseList = dtailsVo.getPhaseList();
		if (!CollectionUtils.isEmpty(phaseList)) {
			Long experimentId = dtailsVo.getExperiment().getId();
			Map<Long, List<ExperimentStepReagent>> reagentMap = experimentStepReagentService
					.selectStepReagentList(experimentId).stream()
					.collect(Collectors.groupingBy(ExperimentStepReagent::getStepId));
			Map<Long, List<PlateStepRelate>> plateMap = plateStepRelateService.selectStepRelateList(experimentId)
					.stream().collect(Collectors.groupingBy(PlateStepRelate::getStepId));
			Map<Long, List<ExperimentStepTimer>> timerMap = experimentStepTimerService.selectStepTimerList(experimentId)
					.stream().collect(Collectors.groupingBy(ExperimentStepTimer::getStepId));
			Map<Long, List<ExperimentProduce>> produceMap = experimentProduceService
					.selectProduceList(experimentId, true).stream()
					.collect(Collectors.groupingBy(ExperimentProduce::getExperimentStepId));

			for (ExperimentPhaseVo phase : phaseList) {
				List<ExperimentStepVo> stepList = phase.getExperimentStepVoList();
				if (!CollectionUtils.isEmpty(stepList)) {
					for (ExperimentStepVo step : stepList) {
						List<Integer> relationList = new ArrayList<Integer>();
						if (StringUtils.isNotBlank(step.getTips())) {
							relationList.add(ExperimentStepRelationEnum.TIPS.getValue());
						}
						if (plateMap != null && plateMap.get(step.getStepId()) != null) {
							relationList.add(ExperimentStepRelationEnum.PLATE.getValue());
						}
						if (reagentMap != null && reagentMap.get(step.getStepId()) != null) {
							relationList.add(ExperimentStepRelationEnum.REAGENT.getValue());
						}
						if (timerMap != null && timerMap.get(step.getStepId()) != null) {
							relationList.add(ExperimentStepRelationEnum.TIMER.getValue());
						}
						if (produceMap != null && produceMap.get(step.getStepId()) != null) {
							relationList.add(ExperimentStepRelationEnum.PRODUCE.getValue());
						}
						String relation = StringUtils.join(relationList, ",");
						step.setRelation(relation);
					}
				}
			}
		}
		return dtailsVo;
	}

	public void experimentHeadModify(ExperimentHeadModifyVo modifyVo) {
		Experiment experiment = new Experiment();
		experiment.setId(modifyVo.getExperimentId());
		if (StringUtils.isNotBlank(modifyVo.getExperimentName())
				|| StringUtils.isNotBlank(modifyVo.getExperimentDescription())) {
			experiment.setName(modifyVo.getExperimentName());
			experiment.setDescription(modifyVo.getExperimentDescription());
		}

		if (modifyVo.getPhaseId() != null) {
			ExperimentPhase phase = experimentPhaseService.selectById(modifyVo.getPhaseId());
			phase.setName(modifyVo.getPhaseName());
			phase.setDescription(modifyVo.getPhaseDescription());
			experimentPhaseService.updateById(phase);
		}
		experiment.setIsNewMethod(BoolEnum.TRUE.getValue());
		experimentService.updateById(experiment);
	}

	public void experimentStepModify(ExperimentStepModifyVo modifyVo) {
		ExperimentStep step = experimentStepService.selectById(modifyVo.getStepId());
		Assert.notNull(step, "步骤信息不存在");

		String content = modifyVo.getContent();
		List<String> uuidList = ReagentUuidsUtil.getReagentUuids(content);
		List<ExperimentStepReagent> reagentList = experimentStepReagentService
				.selectExperimentStepReagentList(step.getExperimentId(), step.getExperimentPhaseId(), step.getId());
		if (CollectionUtils.isEmpty(uuidList) && !CollectionUtils.isEmpty(reagentList)) {
			// stepReagent
			List<Long> idList = reagentList.stream().map(ExperimentStepReagent::getId).collect(Collectors.toList());
			// bill
			List<ExperimentBill> experimentBills = experimentBillService.selectInStepReagentIds(idList);
			List<Long> billIds = experimentBills.stream().map(ExperimentBill::getId).distinct()
					.collect(Collectors.toList());
			if (!CollectionUtils.isEmpty(idList)) {
				experimentStepReagentService.deleteByIds(idList);
			}
			if (CollectionUtils.isNotEmpty(billIds)) {
				experimentBillService.deleteByIds(billIds);
			}
		} else if (!CollectionUtils.isEmpty(uuidList) && !CollectionUtils.isEmpty(reagentList)) {
			// stepReagent
			List<Long> idList = new ArrayList<Long>();
			for (ExperimentStepReagent reagent : reagentList) {
				boolean bool = false;
				for (String uuid : uuidList) {
					if (uuid.equals(reagent.getUuid())) {
						bool = true;
						break;
					}
				}
				if (!bool) {
					idList.add(reagent.getId());
				}
			}
			// bill
			List<ExperimentBill> experimentBills = experimentBillService.selectInStepReagentIds(idList);
			List<Long> billIds = experimentBills.stream().map(ExperimentBill::getId).distinct()
					.collect(Collectors.toList());
			if (!CollectionUtils.isEmpty(idList)) {
				experimentStepReagentService.deleteByIds(idList);
			}
			if (CollectionUtils.isNotEmpty(billIds)) {
				experimentBillService.deleteByIds(billIds);
			}
		}

		step.setContent(modifyVo.getContent());
		experimentStepService.updateById(step);

		experimentService.updateByNewMethod(step.getExperimentId());
	}

	public Long experimentStepInsert(ExperimentStepSaveVo saveVo) {
		List<ExperimentStep> stepList = experimentStepService.selectByPhaseId(saveVo.getPhaseId());
		stepList.forEach(step -> {
			if (step.getSort() >= saveVo.getSort()) {
				step.setSort(step.getSort() + 1);
				experimentStepService.updateById(step);
			}
		});

		ExperimentStep step = new ExperimentStep();
		step.setExperimentId(saveVo.getExperimentId());
		step.setExperimentPhaseId(saveVo.getPhaseId());
		step.setSort(saveVo.getSort());
		step.setState(ExperimentStateEnum.NOT_STARTED.getValue());
		step.setContent(saveVo.getContent());
		step = experimentStepService.insert(step);

		experimentService.updateByNewMethod(step.getExperimentId());
		return step.getId();
	}

	public Long experimentStepDelete(Long stepId) {
		List<ExperimentStep> stepList = new ArrayList<>();
		ExperimentStep step = experimentStepService.selectById(stepId);
		Assert.notNull(step, "步骤不存在");
		List<ExperimentPhase> phaseList = experimentPhaseService.selectList(step.getExperimentId());
		for (ExperimentPhase phase : phaseList) {
			List<ExperimentStep> stepList2 = experimentStepService.selectByPhaseId(phase.getId());
			if (!CollectionUtils.isEmpty(stepList2))
				stepList.addAll(stepList2);
		}
		Assert.isTrue(stepList.size() > 1, "当前只有一个步骤不能删除");

		// 返回上一个步骤的id，如果删除的是第一步，则是返回下一个步骤的id
		Long experimentStepId = null;
		for (int i = 0; i < stepList.size(); i++) {
			if (stepList.get(i).getId().equals(stepId)) {
				if (i == 0) {
					experimentStepId = stepList.get(1).getId();
				} else {
					experimentStepId = stepList.get(i - 1).getId();
				}
				break;
			}
		}
		experimentStepService.deleteById(stepId);

		List<ExperimentStep> stepList3 = experimentStepService.selectByPhaseId(step.getExperimentPhaseId());
		if (!CollectionUtils.isEmpty(stepList3)) {
			for (int i = 0; i < stepList3.size(); i++) {
				ExperimentStep experimentStep = stepList3.get(i);
				experimentStep.setSort(i + 1);
				experimentStepService.updateById(experimentStep);
			}
		}
		experimentService.updateByNewMethod(step.getExperimentId());
		return experimentStepId;
	}

	/**
	 * 开始实验
	 *
	 * @param experimentId
	 */
	public void experimentStart(Long experimentId) {
		Experiment experiment = experimentService.selectById(experimentId);
		if (experiment.getState().equals(ExperimentStateEnum.NOT_STARTED.getValue())) {
			experiment.setState(ExperimentStateEnum.UNDER_WAY.getValue());
			experimentService.updateById(experiment);
		}
	}

	/**
	 * 重复实验步骤
	 *
	 * @param stepId
	 * @param isCurrent 0-重复当前步骤，1-后续全部步骤
	 */
	public void experimentStepRepeat(Long stepId, int isCurrent, UserInfoVo userInfo) {
		ExperimentStep step = experimentStepService.selectById(stepId);

		experimentStepTimerLogic.resetStepTimers(step.getExperimentId(), step.getExperimentPhaseId(), step.getId(),
				userInfo.getLabId(), userInfo.getLabMemberId());

		step.setState(ExperimentStateEnum.UNDER_WAY.getValue());
		experimentStepService.updateById(step);

		if (isCurrent == 1) {
			ExperimentPhase stepPhase = experimentPhaseService.selectById(step.getExperimentPhaseId());
			List<ExperimentPhase> phaseList = experimentPhaseService.selectList(step.getExperimentId());
			if (!CollectionUtils.isEmpty(phaseList)) {
				List<ExperimentStep> stepList = experimentStepService.getExperimentStepList(step.getExperimentId());
				Map<Long, List<ExperimentStep>> stepMap = stepList.stream()
						.collect(Collectors.groupingBy(ExperimentStep::getExperimentPhaseId));
				phaseList.forEach(phase -> {
					if (phase.getSort() > stepPhase.getSort()) {
						List<ExperimentStep> list = stepMap.get(phase.getId());
						if (!CollectionUtils.isEmpty(list)) {
							for (ExperimentStep step2 : list) {
								if (!step2.getState().equals(ExperimentStateEnum.NOT_STARTED.getValue())) {
									step2.setState(ExperimentStateEnum.NOT_STARTED.getValue());
									experimentStepService.updateById(step2);
									experimentStepTimerLogic.resetStepTimers(step2.getExperimentId(),
											step2.getExperimentPhaseId(), step2.getId(), userInfo.getLabId(),
											userInfo.getLabMemberId());
								}
							}
						}
					} else if (phase.getSort() == stepPhase.getSort()) {
						List<ExperimentStep> list = stepMap.get(phase.getId());
						if (!CollectionUtils.isEmpty(list)) {
							for (ExperimentStep step2 : list) {
								if (step2.getSort() > step.getSort()
										&& !step2.getState().equals(ExperimentStateEnum.NOT_STARTED.getValue())) {
									step2.setState(ExperimentStateEnum.NOT_STARTED.getValue());
									experimentStepService.updateById(step2);
									experimentStepTimerLogic.resetStepTimers(step2.getExperimentId(),
											step2.getExperimentPhaseId(), step2.getId(), userInfo.getLabId(),
											userInfo.getLabMemberId());
								}
							}
						}
					}
				});
			}
		}
	}

	/**
	 * 保存产物
	 *
	 * @param saveListVo
	 * @return
	 */
	public List<SampleSpecVo> produceSave(ExperimentProduceSaveListVo saveListVo, UserInfoVo urs) {
		List<SampleSpecVo> voList = new ArrayList<SampleSpecVo>();
		List<ExperimentProduceAttr> attrList = new ArrayList<ExperimentProduceAttr>();
		List<ExperimentProduceSaveVo> produceList = saveListVo.getProduceList();
		if (!CollectionUtils.isEmpty(produceList)) {
			Long kitGroup = kitService.getKitGroup();
			for (ExperimentProduceSaveVo saveVo : produceList) {
				Long kitId = null;
				Long reagentId = null;
				if (BoolEnum.TRUE.getValue().equals(saveListVo.getIsInventory())) {
					SampleAddPa pa = MyBeanUtils.copyBean(saveVo, SampleAddPa.class);
					pa.setLabId(saveListVo.getLabId());
					pa.setCreatorId(saveListVo.getCreatorId());
					pa.setReagentTypeId(saveListVo.getReagentTypeId());
					pa.setAlias(StringUtils.isNotBlank(saveVo.getAlias()) ? saveVo.getAlias() : null);
					pa.setKitGroup(kitGroup);
					List<ExperimentProduceAttr> produceAttrList = saveVo.getProduceAttrList();
					if (!CollectionUtils.isEmpty(produceAttrList)) {
						List<SampleAttrPa> sampleAttrList = new ArrayList<SampleAttrPa>();
						for (ExperimentProduceAttr attr : produceAttrList) {
							SampleAttrPa attrPa = MyBeanUtils.copyBean(attr, SampleAttrPa.class);
							sampleAttrList.add(attrPa);
						}
						pa.setSampleAttrList(sampleAttrList);
					}
					SampleSpecVo specVo = sampleLogic.addSampleOne(pa);
					kitId = specVo.getKitId();
					kitId = specVo.getReagentId();
					voList.add(specVo);
				}

				ExperimentProduce produce = MyBeanUtils.copyBean(saveVo, ExperimentProduce.class);
				produce.setLabId(saveListVo.getLabId());
				produce.setKitId(kitId);
				produce.setReagentId(reagentId);
				produce.setReagentTypeId(saveListVo.getReagentTypeId());
				produce.setAlias(StringUtils.isNotBlank(saveVo.getAlias()) ? saveVo.getAlias() : null);
				produce.setExperimentId(saveListVo.getExperimentId());
				produce.setExperimentPhaseId(saveListVo.getExperimentPhaseId());
				produce.setExperimentStepId(saveListVo.getExperimentStepId());
				if (saveVo.getSize() != null && saveVo.getMultiple() != null) {
					produce.setAmount(saveVo.getSize().multiply(new BigDecimal(saveVo.getMultiple())));
				}
				produce = experimentProduceService.insert(produce);

				List<ExperimentProduceAttr> produceAttrList = saveVo.getProduceAttrList();
				if (!CollectionUtils.isEmpty(produceAttrList)) {
					for (ExperimentProduceAttr attr : produceAttrList) {
						attr.setLabId(saveListVo.getLabId());
						attr.setProduceId(produce.getId());
						attrList.add(attr);
					}
				}
			}
			experimentProduceAttrService.insertBatch(attrList);
		}

		// 添加记录
		List<Long> collect = voList.stream().map(SampleSpecVo::getKitId).distinct().collect(Collectors.toList());
		if (collect.size() > 0) {
			inventoryRecordService.add(urs, collect, InventoryRecordEnum.CREATE);
		}

		experimentStepService.startStep(saveListVo.getExperimentStepId());
		return voList;
	}

	/**
	 * 实验转方法
	 *
	 * @param userInfo
	 * @return
	 */
	public Long experimentToMethod(UserInfoVo userInfo, Experiment experiment) {
		NewMethod newMethod = new NewMethod();
		if (experiment.getMethodId() != null) {
			Method method = methodService.getById(experiment.getMethodId());
			newMethod.setName(method.getName());
		} else {
			newMethod.setName(experiment.getName());
		}
		newMethod.setMethodTypeId(experiment.getMethodTypeId());
		newMethod.setDescription(experiment.getDescription());
		newMethod.setFromType(MethodSourceEnum.CREATE.getSourceType());

		Map<Long, List<ExperimentStepReagent>> reagentMap = experimentStepReagentService
				.selectStepReagentList(experiment.getId()).stream()
				.collect(Collectors.groupingBy(ExperimentStepReagent::getStepId));
		Map<Long, List<ExperimentStepTimer>> timerMap = experimentStepTimerService
				.selectStepTimerList(experiment.getId()).stream()
				.collect(Collectors.groupingBy(ExperimentStepTimer::getStepId));

		List<ExperimentPhase> phaseList = experimentPhaseService.selectList(experiment.getId());
		if (!CollectionUtils.isEmpty(phaseList)) {
			List<NewMethodPhase> methodPhaseList = new ArrayList<>();
			for (ExperimentPhase phase : phaseList) {
				NewMethodPhase methodPhase = new NewMethodPhase();
				methodPhase.setName(phase.getName());
				methodPhase.setSort(phase.getSort());
				methodPhase.setTip(phase.getDescription());
				if (phase.getMethodPhaseId() != null) {
					MethodPhase methodPhase2 = methodPhaseService.selectById(phase.getMethodPhaseId());
					if (methodPhase2 != null) {
						methodPhase.setSourcePhaseId(methodPhase2.getSourcePhaseId());
						methodPhase.setInitPhaseId(methodPhase2.getInitPhaseId());
					}
				}
				List<ExperimentStep> stepList = experimentStepService.selectByPhaseId(phase.getId());
				if (!CollectionUtils.isEmpty(stepList)) {
					List<NewMethodStep> methodStepList = new ArrayList<>();
					for (ExperimentStep step : stepList) {
						NewMethodStep methodStep = new NewMethodStep();
						methodStep.setSort(step.getSort());
						methodStep.setContent(step.getContent());
						if (step.getMethodStepId() != null) {
							MethodStep methodStep2 = methodStepService.selectById(step.getMethodStepId());
							if (methodStep2 != null) {
								methodStep.setSourceStepId(methodStep2.getSourceStepId());
								methodStep.setInitStepId(methodStep2.getInitStepId());
							}
						}
						List<ExperimentStepReagent> reagentList = reagentMap.get(step.getId());
						if (!CollectionUtils.isEmpty(reagentList)) {
							List<MethodRelateReagentVo> reagentVoList = new ArrayList<>();
							for (ExperimentStepReagent reagent : reagentList) {
								MethodRelateReagentVo reagentVo = new MethodRelateReagentVo(null, reagent.getUuid(),
										null, reagent.getReagentId(), reagent.getName(), reagent.getKitId(),
										reagent.getKitName(), reagent.getType(), reagent.getAmount());
								reagentVoList.add(reagentVo);
							}
							methodStep.setReagentVoList(reagentVoList);
						}

						List<ExperimentStepTimer> timerList = timerMap.get(step.getId());
						if (!CollectionUtils.isEmpty(timerList)) {
							List<MethodRelateTimer> timerVoList = new ArrayList<>();
							for (ExperimentStepTimer timer : timerList) {
								MethodRelateTimer timerVo = new MethodRelateTimer();
								timerVo.setTime(timer.getTime());
								timerVoList.add(timerVo);
							}
							methodStep.setTimerList(timerVoList);
						}
						methodStepList.add(methodStep);
					}
					methodPhase.setStepList(methodStepList);
				}
				methodPhaseList.add(methodPhase);
			}
			newMethod.setPhaseList(methodPhaseList);
		}

		if (experiment.getMethodId() != null) {
			Method method = methodService.getById(experiment.getMethodId());
			if (method != null && method.getUserId() != null) {
				newMethod.setSourceMethodId(method.getSourceMethodId());
				newMethod.setInitMethodId(method.getInitMethodId());
				newMethod.setAuthor(method.getAuthor());
				newMethod.setLink(method.getLink());
				newMethod.setFromType(method.getFromType());
				List<FileManage> fileList = fileManageService.selectList(OssFileEnum.Method, method.getId());
				if (!CollectionUtils.isEmpty(fileList)) {
					List<Long> fileIdList = fileList.stream().map(FileManage::getId).collect(Collectors.toList());
					newMethod.setCopyFileIdList(fileIdList);
				}
				return methodLogic.addNewVersion(newMethod, userInfo);
			}
		}
		return methodLogic.addNewMethod(newMethod, userInfo);
	}

	public int commentNum(Long experimentId, Integer type) {
		return experimentCommentService.commentNum(experimentId, type);
	}

	/**
	 * 添加tips
	 *
	 * @param experimentTipsVo
	 * @return
	 */
	public List<FileManage> addTips(ExperimentTipsVo experimentTipsVo, UserInfoVo userInfo) {
		if (experimentTipsVo.getTips() != null) {
			ExperimentStep experimentStep = new ExperimentStep();
			experimentStep.setId(experimentTipsVo.getStepId());
			experimentStep.setTips(experimentTipsVo.getTips());
			experimentStepService.update(experimentStep);
		}

		List<FileManage> fileList = new ArrayList<FileManage>();
		if (experimentTipsVo.isRenewal()) {
			// tips文件PC续传
			if (!CollectionUtils.isEmpty(experimentTipsVo.getTipsFileList())) {
				List<FileManage> analyzeList = fileManageService.insertBatch(experimentTipsVo.getTipsFileList(),
						experimentTipsVo.getStepId(), OssFileEnum.TipFile, userInfo.getLabId(), userInfo.getId());
				fileList.addAll(analyzeList);
			}
		} else {
			// tips文件直传
			if (ArrayUtils.isNotEmpty(experimentTipsVo.getTipsFileIds())) {
				fileManageService.relevanceBatch(experimentTipsVo.getTipsFileIds(), experimentTipsVo.getStepId(),
						OssFileEnum.TipFile, userInfo.getLabId(), userInfo.getId());
				fileList = fileManageService.listByIdList(Arrays.asList(experimentTipsVo.getTipsFileIds()));
			}
		}
		experimentStepService.startStep(experimentTipsVo.getStepId());
		return fileList;
	}

	/**
	 * 获得tips
	 *
	 * @param stepId
	 * @return
	 */
	public ExperimentTipsVo getTips(Long stepId) {
		return experimentStepService.selectExperimentTipsVo(stepId, OssFileFolderEnum.getValue(39));
	}

	/**
	 * 删除tips文本
	 *
	 * @param stepId
	 * @return
	 */
	public void deleteTips(Long stepId) {
		experimentStepService.deleteTips(stepId);
	}

	/**
	 * 实验tips列表
	 *
	 * @param experimentId
	 * @return
	 */
	public List<ExperimentPhaseVo> tipsList(Long experimentId) {
		return experimentPhaseService.selectExperimentStepVoList(experimentId);
	}

	/**
	 * 无方法开始实验
	 *
	 * @param addVo
	 * @return
	 */
	public Map<String, Long> addExperiment(ExperimentAddVo addVo) {
		Experiment experiment = experimentService.selectById(addVo.getExperimentId());
		Assert.notNull(experiment, "有实验进行中不能新建实验");
		experiment.setIsImport(BoolEnum.TRUE.getValue());
		experimentService.updateById(experiment);

		ExperimentPhase phase = new ExperimentPhase();
		phase.setExperimentId(experiment.getId());
		phase.setName(experiment.getName());
		phase.setDescription(experiment.getDescription());
		phase = experimentPhaseService.insert(phase);

		ExperimentStep step = new ExperimentStep();
		step.setExperimentId(experiment.getId());
		step.setExperimentPhaseId(phase.getId());
		step.setContent(addVo.getContent());
		step.setState(ExperimentStateEnum.NOT_STARTED.getValue());
		step = experimentStepService.insert(step);

		Map<String, Long> map = new HashMap<String, Long>();
		map.put("experimentId", experiment.getId());
		map.put("phaseId", phase.getId());
		map.put("stepId", step.getId());
		return map;
	}

	// ***** end *********//

	/**
	 * 实验分组树型结构
	 *
	 * @param experimentId
	 * @return
	 */
	public List<ExperimentGroupRelationTreeVo> getExperimentGroupTree(Long experimentId, UserInfoVo userInfo) {
		Experiment experiment = checkExperiment(experimentId, userInfo.getLabId());
		this.experimentInfoSave(experiment.getId());
		// 获取实验分组关系列表
		List<ExperimentGroupRelation> relationList = experimentGroupRelationService.selectList(experimentId);
		// 根据父id分类
		Map<Long, List<ExperimentGroupRelation>> groupRelation = relationList.stream()
				.collect(Collectors.groupingBy(ExperimentGroupRelation::getParentId));
		// 组装实验分组列表
		return structureTree(0L, groupRelation);
	}

	/**
	 * @Description: 构建实验分组树形结构
	 * @Param [parentId, groupRelation]
	 */
	private List<ExperimentGroupRelationTreeVo> structureTree(Long parentId,
			Map<Long, List<ExperimentGroupRelation>> groupRelation) {
		List<ExperimentGroupRelation> parentList = groupRelation.get(parentId);
		List<ExperimentGroupRelationTreeVo> treeList = new ArrayList<>();
		if (CollectionUtils.isEmpty(parentList)) {
			return treeList;
		}
		parentList.forEach(parent -> {
			ExperimentGroupRelationTreeVo treeVo = new ExperimentGroupRelationTreeVo();
			treeVo.setId(parent.getId());
			treeVo.setContent(parent.getContent());
			treeVo.setType(parent.getType());
			treeVo.setChild(structureTree(parent.getId(), groupRelation));
			treeList.add(treeVo);
		});
		return treeList;
	}

	/**
	 * 保存实验分组
	 *
	 * @param vo
	 * @return
	 */
	public void saveExperimentGroup(ExperimentGroupSaveVo vo, Long labId) {
		checkExperiment(vo.getExperimentId(), labId);
		List<ExperimentGroup> groupList = vo.getGroups();
		// 原有实验分组
		List<ExperimentGroup> oldGroupList = experimentGroupService.selectList(vo.getExperimentId());
		// 重新生成实验分组
		if (!CollectionUtils.isEmpty(oldGroupList)) {
			// 删除原有实验分组
			experimentGroupService
					.deleteByBatch(oldGroupList.stream().map(ExperimentGroup::getId).collect(Collectors.toList()));
			// 删除原有实验分组关联
			experimentGroupRelationService.deleteByExperimentId(vo.getExperimentId());
			List<Long> textIds = experimentStepTextService.selectList(vo.getExperimentId(), 0L, 0L).stream()
					.map(ExperimentStepText::getId).collect(Collectors.toList());
			if (!CollectionUtils.isEmpty(textIds)) {
				// 删除原有实验分组文本
				experimentStepTextService.deleteByExperimentIdAndType(vo.getExperimentId(),
						ExperimentStepTextTypeEnum.GROUP.getValue());
				// 删除原有实验分组文本关联多孔板
				plateGridTextService.deleteByStepTextIds(textIds);
			}
		}
		List<ExperimentGroupRelation> firstRelations = new ArrayList<>();
		List<ExperimentGroupRelation> secondRelations = new ArrayList<>();
		List<ExperimentGroupRelation> threeRelations = new ArrayList<>();
		List<ExperimentStepText> textList = new ArrayList<>();
		groupList.forEach(group -> {
			Assert.isTrue(ExperimentGroupEnum.getKey(group.getType()) != null, "分组类型不存在！");
			group.setExperimentId(vo.getExperimentId());
			ExperimentGroupRelation relation = new ExperimentGroupRelation();
			relation.setContent(group.getContent());
			relation.setType(group.getType());
			relation.setExperimentId(vo.getExperimentId());
			if (group.getType().equals(ExperimentGroupEnum.SAMPLE.getValue())) {
				// 一级列表
				relation.setParentId(0L);
				firstRelations.add(relation);
			} else if (group.getType().equals(ExperimentGroupEnum.HANDLE.getValue())) {
				// 二级列表
				secondRelations.add(relation);
			} else {
				// 三级列表
				threeRelations.add(relation);
			}
			this.addTextList(vo.getExperimentId(), group.getContent(), textList, group.getType());
		});
		// 添加实验分组文本
		experimentStepTextService.insertBatch(textList);
		// 添加实验分组
		experimentGroupService.insertByBatch(groupList);
		// 添加实验分组关系图
		Assert.isTrue(CollectionUtils.isNotEmpty(firstRelations), "实验分组样品不能为空！");
		experimentGroupRelationService.insertBatch(firstRelations);
		// 实验分组关系
		if (CollectionUtils.isNotEmpty(secondRelations)) {
			// 存在二级
			List<ExperimentGroupRelation> secondList = this.setParentId(firstRelations, secondRelations);
			experimentGroupRelationService.insertBatch(secondList);
			if (CollectionUtils.isNotEmpty(threeRelations)) {
				// 存在三级
				List<ExperimentGroupRelation> threeList = this.setParentId(secondList, threeRelations);
				experimentGroupRelationService.insertBatch(threeList);
			}
		} else {
			if (CollectionUtils.isNotEmpty(threeRelations)) {
				// 不存在二级 存在三级
				List<ExperimentGroupRelation> threeRelationList = this.setParentId(firstRelations, threeRelations);
				experimentGroupRelationService.insertBatch(threeRelationList);
			}
		}
	}

	// Nonfat Dry Milk-0-piHGpd/G81S-0_Nonfat Dry
	// Milk-0-piHGpd/G81S-0_pcDNA-p160(400-580)-0-通用19061101-0-123456-0-ABTS™-0
	List<ExperimentGroupRelation> setParentId(List<ExperimentGroupRelation> parentList,
			List<ExperimentGroupRelation> childList) {
		List<ExperimentGroupRelation> childRelationList = new ArrayList<>();
		parentList.forEach(parent -> {
			childList.forEach(child -> {
				ExperimentGroupRelation relation = MyBeanUtils.copyBean(child, ExperimentGroupRelation.class);
				relation.setParentId(parent.getId());
				childRelationList.add(relation);
			});
		});
		return childRelationList;
	}

	private void addTextList(Long experimentId, String content, List<ExperimentStepText> textList, Integer groupType) {
		ExperimentStepText experimentStepText = new ExperimentStepText();
		experimentStepText.setExperimentId(experimentId);
		experimentStepText.setContent(content);
		experimentStepText.setGroupType(groupType);
		experimentStepText.setType(ExperimentStepTextTypeEnum.GROUP.getValue());
		textList.add(experimentStepText);
	}

	/**
	 * @Description: 实验校验
	 * @Param: [experimentId, labId]
	 */
	private Experiment checkExperiment(Long experimentId, Long labId) {
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.isTrue(experiment != null, "实验不存在！");
		Assert.isTrue(experiment.getIsDelete().equals(BoolEnum.FALSE.getValue()), "实验已删除！");
		Assert.isTrue(experiment.getLabId().equals(labId), "不能操作其他实验室实验！");
		return experiment;
	}

	
	
	
	
	/**
	 * 实验分组已有分组列表
	 *
	 * @param experimentId
	 * @return
	 */
	public List<ExperimentGroupMapVo> getAllGroup(Long experimentId, Long labdId) {
		Experiment experiment = checkExperiment(experimentId, labdId);
		List<ExperimentGroupListVo> groupListVoList = experimentGroupService
				.selectByTopicTargetId(experiment.getTopicTargetId());
		List<ExperimentGroupMapVo> result = new ArrayList<>();
		groupListVoList.forEach(group -> {
			Map<String, List<ExperimentGroup>> map = group.getGroups().stream()
					.collect(Collectors.groupingBy(e -> ExperimentGroupEnum.getKey(e.getType())));
			ExperimentGroupMapVo mapVo = new ExperimentGroupMapVo();
			mapVo.setExperimentId(group.getExperimentId());
			mapVo.setExperimentName(group.getExperimentName());
			mapVo.setGroups(map);
			result.add(mapVo);
		});
		return result;
	}

	/**
	 * @Description: 实验评论新增
	 * @Param: [commentVo, userInfo]
	 */
	@Deprecated
	public List<FileManage> addComment(ExperimentCommentAddVo commentVo, UserInfoVo userInfo) {
		// 校验实验
		checkExperiment(commentVo.getExperimentId(), userInfo.getLabId());
		ExperimentComment comment = new ExperimentComment();
		comment.setContent(commentVo.getContent());
		comment.setExperimentId(commentVo.getExperimentId());
		comment.setType(commentVo.getType());
		comment.setLabMemberId(userInfo.getLabMemberId());
		comment = experimentCommentService.addComment(comment);

		List<FileManage> fileList = new ArrayList<>();
		if (commentVo.isRenewal()) {
			// tips文件PC续传
			if (CollectionUtils.isNotEmpty(commentVo.getCommentFileList())) {
				List<FileManage> analyzeList = fileManageService.insertBatch(commentVo.getCommentFileList(),
						comment.getId(), OssFileEnum.CommentFile, userInfo.getLabId(), userInfo.getId());
				fileList.addAll(analyzeList);
			}
		} else {
			// tips文件直传
			if (!ArrayUtils.isEmpty(commentVo.getCommentFileIds())) {
				fileManageService.relevanceBatch(commentVo.getCommentFileIds(), comment.getId(),
						OssFileEnum.CommentFile, userInfo.getLabId(), userInfo.getId());
			}
		}
		return fileList;
	}

	/**
	 * @Description: 实验评论列表
	 * @Param: [experimentId, labId]
	 */
	public List<ExperimentCommentVo> commentList(Long experimentId, Integer type, UserInfoVo userInfo) {
		checkExperiment(experimentId, userInfo.getLabId());
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在!");
		this.experimentInfoSave(experiment.getId());
		// 如果实验执行人查看实验评论，设置已读
		if (userInfo.getLabMemberId().equals(experiment.getExecutorId())) {
			experimentCommentService.setReadState(experimentId);
		}
		List<ExperimentCommentVo> commentVoList = experimentCommentService.selectList(experimentId, type);
		if (CollectionUtils.isNotEmpty(commentVoList)) {
			commentVoList.forEach(commentVo -> {
				List<FileManage> commentFileList = fileManageService.selectList(OssFileEnum.CommentFile,
						commentVo.getId());
				Map<Integer, List<FileManage>> fileMap = commentFileList.stream()
						.collect(Collectors.groupingBy(FileManage::getFileType));
				List<FileManage> ImgVideoFileList = new ArrayList<>();
				if (fileMap.get(3) != null)
					ImgVideoFileList.addAll(fileMap.get(3));
				if (fileMap.get(2) != null)
					ImgVideoFileList.addAll(fileMap.get(2));
				commentVo.setImgVideoFileList(ImgVideoFileList);

				commentVo.setAudioFileList(fileMap.get(1));
			});
		}
		return commentVoList;
	}

	/**
	 * @Description: 实验评论删除
	 * @Param: [commentId, userInfoVo]
	 */
	public void deleteComment(Long commentId, UserInfoVo userInfoVo) {
		ExperimentComment comment = experimentCommentService.selectById(commentId);
		Assert.isTrue(comment != null, "实验评论不存在!");
		Experiment experiment = experimentService.selectById(comment.getExperimentId());
		Assert.isTrue(experiment.getLabId().equals(userInfoVo.getLabId())
				&& comment.getLabMemberId().equals(userInfoVo.getLabMemberId()), "没有权限操作!");
		experimentCommentService.deleteComment(commentId);
		fileManageService.deleteByAttachTypeAndReferDataId(OssFileEnum.CommentFile, commentId);
	}

	/**
	 * TroubleShooting新增或编辑（取决troubleShootingId是否为空
	 *
	 * @param listVo
	 * @param userInfo
	 */
	public void addTroubleShooting(ExperimentTroubleShootingVo listVo, UserInfoVo userInfo) {

		experimentService.endExperiment(listVo.getExperimentId(), null);
		List<Long> oldTroubleShooting = new ArrayList<>();
		// 获取DB已有的TroubleShooting
		List<Long> alreadyTroubleShooting = experimentTroubleShootingService.selectIds(listVo.getExperimentId());
		List<ReasonAndDealVo> troubleShootingList = listVo.getTroubleShootingList();
		if (CollectionUtils.isEmpty(troubleShootingList)) {
			experimentTroubleShootingService.deleteByExperimentId(listVo.getExperimentId());
		} else {
			// 修改实验为不符合预期
			Experiment experiment = experimentService.selectById(listVo.getExperimentId());
			experiment.setIsExpect(0);
			experimentService.updateById(experiment);
			troubleShootingList.forEach(reasonAndDealVo -> {
				ExperimentTroubleShooting ets = new ExperimentTroubleShooting();
				ets.setExperimentId(listVo.getExperimentId());
				String reasonContent = reasonAndDealVo.getReason().getContent();
				ets.setReasonContent(StringUtils.trimToEmpty(reasonContent));
				String dealContent = reasonAndDealVo.getDeal().getContent();
				ets.setDealContent(StringUtils.trimToEmpty(dealContent));
				Long[] r = reasonAndDealVo.getReason().getFileIds();
				Long[] d = reasonAndDealVo.getDeal().getFileIds();
				List<Long> reasonFileIds = null;
				List<Long> dealFileIds = null;
				if (r != null && r.length > 0) {
					reasonFileIds = new ArrayList<>(Arrays.asList(r));
				}
				if (d != null && d.length > 0) {
					dealFileIds = new ArrayList<>(Arrays.asList(d));
				}
				// 如果id不为空，则为编辑troubleShooting
				if (reasonAndDealVo.getId() != null) {
					oldTroubleShooting.add(reasonAndDealVo.getId());
					ets.setId(reasonAndDealVo.getId());
					// 更新已有
					ets = experimentTroubleShootingService.update(ets);
					if (CollectionUtils.isNotEmpty(reasonFileIds)) {
						List<Long> oldReasonFileIds = fileManageService
								.selectFileIdArray(OssFileEnum.TroubleShootingReason, reasonAndDealVo.getId());
						reasonFileIds.removeAll(oldReasonFileIds);
					}
					if (CollectionUtils.isNotEmpty(dealFileIds)) {
						List<Long> oldDealFileIds = fileManageService.selectFileIdArray(OssFileEnum.TroubleShootingDeal,
								reasonAndDealVo.getId());
						dealFileIds.removeAll(oldDealFileIds);
					}
				} else {
					ets = experimentTroubleShootingService.insert(ets);
				}
				if (CollectionUtils.isNotEmpty(reasonFileIds)) {
					fileManageService.relevanceBatch(reasonFileIds.toArray(new Long[reasonFileIds.size()]), ets.getId(),
							OssFileEnum.TroubleShootingReason, userInfo.getLabId(), userInfo.getId());
				}
				if (CollectionUtils.isNotEmpty(dealFileIds)) {
					fileManageService.relevanceBatch(dealFileIds.toArray(new Long[dealFileIds.size()]), ets.getId(),
							OssFileEnum.TroubleShootingDeal, userInfo.getLabId(), userInfo.getId());
				}
			});
			// 删除废弃TroubleShooting
			alreadyTroubleShooting.removeAll(oldTroubleShooting);
			if (CollectionUtils.isNotEmpty(alreadyTroubleShooting)) {
				experimentTroubleShootingService.deleteBatchById(alreadyTroubleShooting);
			}
		}
	}

	/**
	 * 获取TroubleShooting
	 *
	 * @param experimentId
	 * @return
	 */
	public List<ExperimentTroubleShootingListVo> getTroubleShooting(Long experimentId) {
		List<ExperimentTroubleShooting> troubleShootingList = experimentTroubleShootingService
				.selectByExperimentId(experimentId);
		List<ExperimentTroubleShootingListVo> troubleShootingInfoVos = new ArrayList<>();
		troubleShootingList.forEach(t -> {
			ExperimentTroubleShootingListVo shootingListVo = new ExperimentTroubleShootingListVo();
			BeanUtils.copyProperties(t, shootingListVo);
			List<FileManage> reasonFileManages = fileManageService.selectList(OssFileEnum.TroubleShootingReason,
					t.getId());
			reasonFileManages.forEach(r -> {
				if (r.getFileType().equals(FileTypeEnum.Video.getValue())
						|| r.getFileType().equals(FileTypeEnum.Image.getValue())) {
					shootingListVo.getReasonImageVideoList().add(r);
				} else if (r.getFileType().equals(FileTypeEnum.Audio.getValue())) {
					shootingListVo.getReasonAudioList().add(r);
				}
			});
			List<FileManage> dealFileManages = fileManageService.selectList(OssFileEnum.TroubleShootingDeal, t.getId());
			dealFileManages.forEach(d -> {
				if (d.getFileType().equals(FileTypeEnum.Video.getValue())
						|| d.getFileType().equals(FileTypeEnum.Image.getValue())) {
					shootingListVo.getDealImageVideoList().add(d);
				} else if (d.getFileType().equals(FileTypeEnum.Audio.getValue())) {
					shootingListVo.getDealAudioList().add(d);
				}
			});
			troubleShootingInfoVos.add(shootingListVo);
		});
		return troubleShootingInfoVos;
	}

	public List<ExperimentTroubleShootingListVo> getLastTroubleShooting(Long experimentId) {
		List<Experiment> experimentList = experimentService.selectLastExperiment(experimentId);
		List<ExperimentTroubleShootingListVo> troubleShootings = new ArrayList<>();
		if (CollectionUtils.isEmpty(experimentList)) {
			return troubleShootings;
		}
		troubleShootings = getTroubleShooting(experimentList.get(0).getId());
		return troubleShootings;
	}

	/**
	 * TroubleShooting方法/试剂/分组
	 *
	 * @param experimentId
	 * @return
	 */
	public ExperimentTroubleShootingMattersVo troubleShootingMatters(Long experimentId, UserInfoVo userInfo) {
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在!");
		this.experimentInfoSave(experiment.getId());

		ExperimentTroubleShootingMattersVo shootingMattersVo = new ExperimentTroubleShootingMattersVo();

		List<ExperimentPhase> phaseList = experimentTroubleShootingService.selectExperimentPhase(experimentId);
		List<ExperimentStep> stepList = experimentTroubleShootingService.selectExperimentStep(experimentId);
		List<ExperimentStepSimple> stepSimpleList = new ArrayList<>();
		phaseList.forEach(p -> {
			stepList.forEach(s -> {
				if (s.getExperimentPhaseId().equals(p.getId())) {
					ExperimentStepSimple stepSimple = new ExperimentStepSimple();
					stepSimple.setId(p.getId());
					stepSimple.setSort(p.getSort() + "." + s.getSort());
					stepSimple.setContent(s.getContent());
					stepSimpleList.add(stepSimple);
				}
			});
		});
		shootingMattersVo.setExperimentMethod(stepSimpleList);
		shootingMattersVo.setReagent(getExperimentReagent(experimentId, null, null));
		shootingMattersVo.setGroup(experimentTroubleShootingService.selectExperimentGroupList(experimentId));
		return shootingMattersVo;
	}

	/**
	 * 根据experimentId获取试剂列表
	 *
	 * @param experimentId
	 * @return
	 */
	public List<ExperimentKitInfoListVo> getExperimentReagent(Long experimentId, Long phaseId, Long stepId) {

		// bill
		List<ExperimentBill> bills;
		if (phaseId != null && stepId != null) {
			bills = experimentBillService.selectList(experimentId, phaseId, stepId);
		} else {
			bills = experimentBillService.selectList(experimentId);
		}
		List<ExperimentBill> reagentBills = bills.stream()
				.filter(e -> ExperimentBillSourceEnum.REAGENT.getSource().equals(e.getSource()))
				.collect(Collectors.toList());
		List<ExperimentBill> productBills = bills.stream()
				.filter(e -> ExperimentBillSourceEnum.EXPERIMENT_PRODUCT.getSource().equals(e.getSource()))
				.collect(Collectors.toList());

		List<Long> reagentIds = reagentBills.stream().map(ExperimentBill::getSourceId).distinct()
				.collect(Collectors.toList());
		List<Long> productIds = productBills.stream().map(ExperimentBill::getSourceId).distinct()
				.collect(Collectors.toList());

		// reagent produce
		List<Reagent> reagents = reagentService.selectByReagentIds(reagentIds);
		List<ExperimentProduce> experimentProduces = experimentProduceService.selectList(productIds);

		// kit file unit
		List<Long> kitIds = reagents.stream().map(Reagent::getKitId).distinct().collect(Collectors.toList());
		List<Kit> kits = kitService.selectByIds(kitIds);
		List<FileManage> fileManages = fileManageService.selectList(OssFileEnum.KitInstructionFile, kitIds);
		Map<Integer, String> unitMap = dictService.getUnitMap();

		List<ExperimentKitInfoListVo> reagentKitInfoList = reagents.stream().map(reagent -> {
			List<ExperimentBill> thisBills = reagentBills.stream().filter(e -> e.getSourceId().equals(reagent.getId()))
					.collect(Collectors.toList());
			ExperimentBill reagentBill = thisBills.isEmpty() ? null : thisBills.get(0);
			if (reagentBill != null) {
				Kit kit = kits.stream().filter(e -> e.getId().equals(reagent.getKitId())).findFirst().orElse(null);
				if (kit != null) {
					ExperimentKitInfoListVo kitInfo = new ExperimentKitInfoListVo();
					kitInfo.setExperimentId(experimentId);
					kitInfo.setSource(reagentBill.getSource());
					kitInfo.setSourceId(reagentBill.getSourceId());
					kitInfo.setKitName(reagent.getName());
					kitInfo.setKitType(KitEnum.Classify.REAGENT.getValue().equals(kit.getClassify()) ? kit.getKitType()
							: kit.getClassify());
					kitInfo.setUnit(reagent.getUnit());
					kitInfo.setUnitName(unitMap.get(reagent.getUnit()));
					kitInfo.setReagentTypeId(reagent.getReagentTypeId());
					List<FileManage> fileList = fileManages.stream().filter(e -> e.getReferDataId().equals(kit.getId()))
							.collect(Collectors.toList());
					kitInfo.setInstructionFileList(fileList);
					for (ExperimentBill bill : thisBills) {
						if (bill.getStepId() != null) {
							kitInfo.setHasRelateStep(true);
							break;
						}
					}
					return kitInfo;
				}
			}
			return null;
		}).filter(Objects::nonNull).collect(Collectors.toList());

		List<ExperimentKitInfoListVo> produceKitInfoList = experimentProduces.stream().map(produce -> {
			ExperimentBill produceBill = productBills.stream().filter(e -> e.getSourceId().equals(produce.getId()))
					.findFirst().orElse(null);
			if (produceBill != null) {
				ExperimentKitInfoListVo kitInfo = new ExperimentKitInfoListVo();
				kitInfo.setExperimentId(experimentId);
				kitInfo.setSource(produceBill.getSource());
				kitInfo.setSourceId(produceBill.getSourceId());
				kitInfo.setKitName(produce.getName());
				kitInfo.setKitType(KitEnum.Classify.SAMPLE.getValue());
				kitInfo.setUnit(produce.getUnit());
				kitInfo.setUnitName(unitMap.get(produce.getUnit()));
				kitInfo.setReagentTypeId(produce.getReagentTypeId());
				kitInfo.setHasRelateStep(produceBill.getStepId() != null);
				return kitInfo;
			}
			return null;
		}).filter(Objects::nonNull).collect(Collectors.toList());
		reagentKitInfoList.addAll(produceKitInfoList);

		return reagentKitInfoList;
	}

	/**
	 * 分析后数据-新增/替换
	 *
	 * @param dataVo
	 * @param userInfo
	 */
	public AnalyzeDataAddReturnVo addAnalyzeData(AnalyzeDataVo dataVo, UserInfoVo userInfo) {
		long experimentId = dataVo.getExperimentId();
		experimentService.endExperiment(experimentId, null);
		List<FileManage> analyzeDataFileList = fileManageService.selectList(OssFileEnum.AnalyzeDataFile, experimentId);
		// 删除已存在附件
		if (dataVo.getOriginFileId() != null && dataVo.getCompressFileId() != null) {
			// 直传情况
			if (analyzeDataFileList.size() > 1) {
				fileManageService.deleteByAttachTypeAndReferDataId(OssFileEnum.AnalyzeDataFile, experimentId,
						dataVo.getOriginFileId());
				fileManageService.deleteByAttachTypeAndReferDataId(OssFileEnum.AnalyzeDataFileThumbnail, experimentId,
						dataVo.getCompressFileId());
			}
		} else {
			// 续传情况
			if (CollectionUtils.isNotEmpty(analyzeDataFileList)) {
				// 删除旧关联数据，标记删除
				deleteAnalyzeDate(experimentId);
			}
		}
		AnalyzeDataAddReturnVo vo = new AnalyzeDataAddReturnVo();
		vo.setExperimentId(experimentId);
		if (dataVo.getOriginFile() != null) {
			List<FileManage> originFile = fileManageService.insertBatch(Arrays.asList(dataVo.getOriginFile()),
					experimentId, OssFileEnum.AnalyzeDataFile, userInfo.getLabId(), userInfo.getId());
			vo.setOriginFile(originFile.get(0));
		}
		if (dataVo.getCompressFile() != null) {
			List<FileManage> compressFile = fileManageService.insertBatch(Arrays.asList(dataVo.getCompressFile()),
					experimentId, OssFileEnum.AnalyzeDataFileThumbnail, userInfo.getLabId(), userInfo.getId());
			vo.setCompressFile(compressFile.get(0));
		}
		return vo;
	}

	/**
	 * 分析后数据-获取
	 *
	 * @param experimentId
	 * @return
	 */
	public FileManage getAnalyzeData(Long experimentId) {
		List<FileManage> originFileManages = fileManageService.selectList(OssFileEnum.AnalyzeDataFile, experimentId);
		Assert.isTrue(CollectionUtils.isNotEmpty(originFileManages), "没有分析后数据！");
		return originFileManages.get(0);
	}

	/**
	 * 分析后数据-删除(续传
	 *
	 * @param experimentId
	 * @return
	 */
	public void deleteAnalyzeDate(Long experimentId) {
		fileManageService.deleteByAttachTypeAndReferDataId(OssFileEnum.AnalyzeDataFile, experimentId);
		fileManageService.deleteByAttachTypeAndReferDataId(OssFileEnum.AnalyzeDataFileThumbnail, experimentId);
	}

	/**
	 * 实验评价设置
	 *
	 * @param evaluationVo
	 */
	public void evaluationSetting(EvaluationVo evaluationVo) {
		Experiment experiment = experimentService.selectById(evaluationVo.getExperimentId());
		Assert.notNull(experiment, "实验不存在");

		if (experiment.getIsExpect() == null && experiment.getMethodId() != null) {
			Method method = methodService.getById(experiment.getMethodId());
			if (method != null) {
				if (BoolEnum.TRUE.getValue().equals(evaluationVo.getResult())) {
					method.setSuccessCount(method.getSuccessCount() + 1);
				}
				method.setExportCount(method.getExportCount() + 1);
				methodService.updateById(method);
			}
		}

		experimentService.endExperiment(experiment.getId(), null);
		experimentService.evaluationSetting(experiment.getId(), evaluationVo.getResult(), evaluationVo.getPublish());

		List<Experiment> publishList = experimentService.getPublishList(experiment.getTopicExperimentId());
		if (CollectionUtils.isNotEmpty(publishList)) {
			TopicExperiment topicExperiment = new TopicExperiment();
			topicExperiment.setId(experiment.getTopicExperimentId());
			topicExperiment.setIsPublish(BoolEnum.TRUE.getValue());
			topicExperimentService.updateById(topicExperiment);
		} else {
			TopicExperiment topicExperiment = new TopicExperiment();
			topicExperiment.setId(experiment.getTopicExperimentId());
			topicExperiment.setIsPublish(BoolEnum.FALSE.getValue());
			topicExperimentService.updateById(topicExperiment);
		}
	}

	/**
	 * 实验试剂列表
	 *
	 * @param experimentId
	 * @return
	 */
	public ExperimentReagentVo getExperimentReagentList(Long experimentId, Long phaseId, Long stepId,
			UserInfoVo userInfo) {

		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在!");
		this.experimentInfoSave(experiment.getId());

		ExperimentReagentVo kitVo = new ExperimentReagentVo();
		List<ExperimentKitInfoListVo> kitInfoListVos = getExperimentReagent(experimentId, phaseId, stepId);
		List<ExperimentKitInfoListVo> kit = new ArrayList<>();
		List<ExperimentKitInfoListVo> sample = new ArrayList<>();
		kitInfoListVos.forEach(k -> {
			if (k.getKitType().equals(KitEnum.KitType.ONE.getValue())
					|| k.getKitType().equals(KitEnum.KitType.MORE.getValue())) {
				kit.add(k);
			} else {
				sample.add(k);
			}
		});
		kitVo.setKit(kit);
		kitVo.setSample(sample);
		return kitVo;
	}

	/**
	 * 原始数据 新增
	 *
	 * @param primaryDataVo
	 * @param userInfo
	 */
	public PrimaryDataAddReturnVo primaryData(PrimaryDataVo primaryDataVo, UserInfoVo userInfo) {
		long experimentId = primaryDataVo.getExperimentId();
		experimentService.endExperiment(experimentId, null);
		PrimaryDataAddReturnVo vo = new PrimaryDataAddReturnVo();
		List<FileManage> fileManageList = new ArrayList<>();
		if (ArrayUtils.isNotEmpty(primaryDataVo.getFileIds())) {
			// 直传
			fileManageService.relevanceBatch(primaryDataVo.getFileIds(), experimentId, OssFileEnum.PrimaryDataFile,
					userInfo.getLabId(), userInfo.getId());
		}
		if (CollectionUtils.isNotEmpty(primaryDataVo.getFileList())) {
			// 续传
			List<FileManage> analyzeList = fileManageService.insertBatch(primaryDataVo.getFileList(), experimentId,
					OssFileEnum.PrimaryDataFile, userInfo.getLabId(), userInfo.getId());
			fileManageList.addAll(analyzeList);
			vo.setExperimentId(experimentId);
			vo.setFileList(fileManageList);
		}
		return vo;
	}

	/**
	 * 原始数据 列表
	 *
	 * @param experimentId
	 * @return
	 */
	public List<FileManage> primaryDateList(Long experimentId, UserInfoVo userInfo) {
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在!");
		this.experimentInfoSave(experiment.getId());
		return fileManageService.selectList(OssFileEnum.PrimaryDataFile, experimentId);
	}

	/**
	 * 方法切换
	 *
	 * @param experimentId
	 * @param newMethodId
	 * @param userInfo
	 * @return
	 * @author WuMenghao
	 */
	public boolean changeExperimentMethod(Long experimentId, Long newMethodId, Long globalKitId, UserInfoVo userInfo) {

		// 删除实验相关信息
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在!");
		Assert.isTrue(experiment.getIsDelete().equals(BoolEnum.FALSE.getValue()), "实验已被删除!");
		Assert.isTrue(experiment.getExecutorId().equals(userInfo.getLabMemberId()), "您不是实验执行人，无法进行该操作!");
		Assert.isTrue(experiment.getState().equals(ExperimentStateEnum.NOT_STARTED.getValue()), "实验已开始，无法进行该操作!");
		experimentPhaseService.deleteByExperimentId(experimentId);
		experimentStepService.deleteByExperimentId(experimentId);
		experimentStepContentLogic.deleteAllContents(experimentId);

		// 方法信息
		Method method = methodService.getById(newMethodId);
		Assert.notNull(method, "方法不存在!");
		Assert.isTrue(method.getIsDelete().equals(BoolEnum.FALSE.getValue()), "方法已被删除!");

		// TODO 非私人方法复制一份
		LabMember labMember = labMemberService.selectById(userInfo.getLabMemberId());
		Assert.notNull(labMember, "成员不存在!");
		if (method.getUserId()!=null){
			// 他人方法复制
			if (!method.getUserId().equals(labMember.getUserId())) {
				Long newId = methodLogic.copyMethodFromMainExecutor(newMethodId, userInfo);
				method = methodService.getById(newId);
			}
		}else {
			// 参考方法直接导入
			method = methodLogic.importMethod(method.getId(), globalKitId, userInfo);
		}

		List<MethodPhase> methodPhases = methodPhaseService.listByMethodId(method.getId(), BoolEnum.FALSE);
		List<MethodStep> methodSteps = methodStepService.listByMethodId(method.getId(), BoolEnum.FALSE);
		List<MethodRelateReagent> methodRelateReagents = methodRelateReagentService
				.listMethodRelateReagentByMethodId(method.getId());
		List<MethodRelateTimer> methodRelateTimers = methodRelateTimerService.getByMethodId(method.getId());

		// 更新实验信息
		MethodTypeDetailVo typeDetailVo = methodTypeService.getMethodFullNameByThirdId(method.getMethodTypeId());
		experiment.setFirstTypeId(typeDetailVo.getFirstTypeId());
		experiment.setMethodTypeId(method.getMethodTypeId());
		experiment.setMethodId(method.getId());
		experimentService.updateById(experiment);
		// 更新实验目标信息
		TopicExperiment topicExperiment = topicExperimentService.selectById(experiment.getTopicExperimentId());
		Assert.notNull(topicExperiment, "实验目标不存在!");
		topicExperiment.setFirstTypeId(typeDetailVo.getFirstTypeId());
		topicExperiment.setMethodTypeId(method.getMethodTypeId());
		topicExperiment.setMethodTypeName(typeDetailVo.getMethodTypeName());
		topicExperiment.setMethodId(method.getId());
		topicExperimentService.updateById(topicExperiment);

		// 新阶段和步骤插入
		List<ExperimentPhase> newPhases = methodPhases.stream().map(methodPhase -> {
			ExperimentPhase phase = new ExperimentPhase();
			phase.setExperimentId(experimentId);
			phase.setName(methodPhase.getName());
			phase.setDescription(methodPhase.getTip());
			phase.setSort(methodPhase.getSort());
			phase.setMethodPhaseId(methodPhase.getId());
			return phase;
		}).collect(Collectors.toList());
		experimentPhaseService.insertBatch(newPhases);
		List<ExperimentStep> newSteps = methodSteps.stream().map(methodStep -> {
			ExperimentPhase phase = newPhases.stream()
					.filter(e -> e.getMethodPhaseId().equals(methodStep.getMethodPhaseId())).findFirst().orElse(null);
			if (phase != null) {
				ExperimentStep step = new ExperimentStep();
				step.setExperimentId(experimentId);
				step.setExperimentPhaseId(phase.getId());
				step.setSort(methodStep.getSort());
				step.setContent(methodStep.getContent());
				step.setMethodStepId(methodStep.getId());
				return step;
			}
			return null;
		}).filter(Objects::nonNull).collect(Collectors.toList());
		experimentStepService.insertBatch(newSteps);

		List<Long> reagentIds = methodRelateReagents.stream().map(MethodRelateReagent::getReagentId).distinct()
				.collect(Collectors.toList());
		List<Reagent> reagents = reagentService.selectByReagentIds(reagentIds);
		List<Long> reagentTypeIds = reagents.stream().map(Reagent::getReagentTypeId).distinct()
				.collect(Collectors.toList());
		Map<Long, Long> firstIdMap = reagentTypeService.selectFirstReagentTypeMap(reagentTypeIds);
		Map<Integer, String> unitMap = dictService.getUnitMap();
		// 新关联试剂和时间插入
		List<ExperimentStepReagent> stepReagents = methodRelateReagents.stream().map(methodRelateReagent -> {
			ExperimentPhase phase = newPhases.stream()
					.filter(e -> e.getMethodPhaseId().equals(methodRelateReagent.getPhaseId())).findFirst()
					.orElse(null);
			ExperimentStep step = newSteps.stream()
					.filter(e -> e.getMethodStepId().equals(methodRelateReagent.getStepId())).findFirst().orElse(null);
			if (phase != null && step != null) {
				Reagent reagent = reagents.stream().filter(e -> e.getId().equals(methodRelateReagent.getReagentId()))
						.findFirst().orElse(null);
				if (reagent != null) {
					ExperimentStepReagent stepReagent = new ExperimentStepReagent();
					stepReagent.setExperimentId(experimentId);
					stepReagent.setPhaseId(phase.getId());
					stepReagent.setStepId(step.getId());
					stepReagent.setUuid(methodRelateReagent.getUuid());
					stepReagent.setReagentId(methodRelateReagent.getReagentId());
					stepReagent.setFirstReagentTypeId(firstIdMap.get(reagent.getReagentTypeId()));
					stepReagent.setClassify(reagent.getClassify());
					stepReagent.setName(reagent.getName());
					stepReagent.setAlias(reagent.getAlias());
					stepReagent.setAmount(methodRelateReagent.getAmount());
					stepReagent.setUnit(unitMap.get(reagent.getUnit()));
					return stepReagent;
				}
			}
			return null;
		}).filter(Objects::nonNull).collect(Collectors.toList());
		experimentStepReagentService.insertBatch(stepReagents);

		List<ExperimentBill> experimentBills = stepReagents.stream().map(stepReagent -> {
			ExperimentPhase phase = newPhases.stream().filter(e -> e.getId().equals(stepReagent.getPhaseId()))
					.findFirst().orElse(null);
			ExperimentStep step = newSteps.stream().filter(e -> e.getId().equals(stepReagent.getStepId())).findFirst()
					.orElse(null);
			if (phase != null && step != null) {
				Reagent reagent = reagents.stream().filter(e -> e.getId().equals(stepReagent.getReagentId()))
						.findFirst().orElse(null);
				if (reagent != null) {
					ExperimentBill bill = new ExperimentBill();
					bill.setExperimentId(experimentId);
					bill.setPhaseId(phase.getId());
					bill.setPhaseSort(phase.getSort());
					bill.setStepId(step.getId());
					bill.setStepSort(step.getSort());
					bill.setAlias(stepReagent.getAlias());
					bill.setName(stepReagent.getName());
					bill.setClassify(stepReagent.getClassify());
					bill.setSource(ExperimentBillSourceEnum.REAGENT.getSource());
					bill.setSourceId(reagent.getId());
					bill.setStepReagentId(stepReagent.getId());
					bill.setFirstReagentTypeId(stepReagent.getFirstReagentTypeId());
					bill.setAmount(stepReagent.getAmount());
					bill.setUnit(reagent.getUnit());
					bill.setIsMethod(BoolEnum.FALSE.getValue());
					return bill;
				}
			}
			return null;
		}).filter(Objects::nonNull).collect(Collectors.toList());
		experimentBillService.insertBatch(experimentBills);

		List<ExperimentStepTimer> stepTimers = methodRelateTimers.stream().map(methodRelateTimer -> {
			ExperimentPhase phase = newPhases.stream()
					.filter(e -> e.getMethodPhaseId().equals(methodRelateTimer.getPhaseId())).findFirst().orElse(null);
			ExperimentStep step = newSteps.stream()
					.filter(e -> e.getMethodStepId().equals(methodRelateTimer.getStepId())).findFirst().orElse(null);
			if (phase != null && step != null) {
				ExperimentStepTimer stepTimer = new ExperimentStepTimer();
				stepTimer.setExperimentId(experimentId);
				stepTimer.setPhaseId(phase.getId());
				stepTimer.setStepId(step.getId());
				stepTimer.setTime(methodRelateTimer.getTime());
				stepTimer.setState(ExperimentStepTimerStateEnum.NOT_START.getState());
				stepTimer.setRemainTime(methodRelateTimer.getTime());
				return stepTimer;
			}
			return null;
		}).collect(Collectors.toList());
		experimentStepTimerService.insertBatch(stepTimers);

		return true;
	}

	/**
	 * 方法详情
	 *
	 * @param experimentId
	 * @param labId
	 * @return
	 * @author WuMenghao
	 */
	public MethodDetail getExperimentMethodDetail(Long experimentId, Long labId) {
		// 实验
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在!");
		Assert.isTrue(experiment.getIsDelete().equals(BoolEnum.FALSE.getValue()), "实验已被删除!");
		Assert.isTrue(experiment.getLabId().equals(labId), "您无法查看其他实验室的试验记录!");
		// 阶段
		List<ExperimentPhase> phases = experimentPhaseService.selectList(experimentId);
		// 步骤
		List<ExperimentStep> steps = experimentStepService.selectListByExperimentId(experimentId);
		// 无方法 无内容
		if (experiment.getMethodId() == null && CollectionUtils.isNotEmpty(phases)
				&& CollectionUtils.isNotEmpty(steps)) {
			return null;
		}
		// 方法
		Method method = methodService.getById(experiment.getMethodId());
		Assert.notNull(method, "方法不存在!");
		MethodTypeDetailVo typeDetailVo = methodTypeService.getMethodFullNameByThirdId(method.getMethodTypeId());
		Assert.notNull(method, "方法类型不存在!");

		MethodDetail detail = MyBeanUtils.copyBean(method, MethodDetail.class);
		List<MethodPhaseDetail> methodPhaseDetails = phases.stream().map(phase -> {
			MethodPhaseDetail mpd = new MethodPhaseDetail();
			List<ExperimentStep> phaseSteps = steps.stream().filter(e -> e.getExperimentPhaseId().equals(phase.getId()))
					.collect(Collectors.toList());
			List<MethodStepDetail> methodStepDetails = phaseSteps.stream().map(step -> {
				MethodStepDetail msd = new MethodStepDetail();
				msd.setId(step.getId());
				msd.setMethodId(experiment.getMethodId());
				msd.setMethodPhaseId(phase.getId());
				msd.setSort(step.getSort());
				msd.setContent(step.getContent());
				msd.setIsDelete(step.getIsDelete());
				return msd;
			}).collect(Collectors.toList());
			mpd.setId(phase.getId());
			mpd.setMethodId(experiment.getMethodId());
			mpd.setName(phase.getName());
			mpd.setTip(phase.getDescription());
			mpd.setSort(phase.getSort());
			mpd.setIsDelete(phase.getIsDelete());
			mpd.setStepList(methodStepDetails);
			return mpd;
		}).collect(Collectors.toList());
		detail.setMethodTypeName(typeDetailVo.getMethodTypeName());
		detail.setThirdTypeName(typeDetailVo.getMethodTypeName());
		detail.setPhaseList(methodPhaseDetails);
		detail.setFirstTypeId(typeDetailVo.getFirstTypeId());
		detail.setFirstTypeName(typeDetailVo.getFirstTypeName());
		detail.setSecondTypeId(typeDetailVo.getSecondTypeId());
		detail.setSecondTypeName(typeDetailVo.getSecondTypeName());
		return detail;
	}

	/**
	 * 实验产出列表
	 *
	 * @param experimentId
	 * @param labId
	 * @return
	 * @author WuMenghao
	 */
	public List<ExperimentProduceListGroupVo> getExperimentProductions(Long experimentId, Long labId) {
		// 校验
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在!");
		Assert.isTrue(experiment.getIsDelete().equals(BoolEnum.FALSE.getValue()), "实验已被删除!");
		Assert.isTrue(experiment.getLabId().equals(labId), "您无法查看其他实验室的试验记录!");

		// 查询
		List<ExperimentProduce> produces = experimentProduceService.selectProduceList(experimentId, false);
		List<Long> typeIds = produces.stream().map(ExperimentProduce::getReagentTypeId).distinct()
				.collect(Collectors.toList());
		List<ReagentType> reagentTypes = reagentTypeService.getSelectedPublicReagentTypeList(typeIds);

		Map<Integer, String> unitMap = dictService.getUnitMap();
		// 封装结果
		List<ExperimentProduceListGroupVo> rs = getExperimentProduceListGroupVos(produces, reagentTypes, unitMap,
				false);

		return rs;
	}

	/* 获取ExperimentProduceListGroupVo */
	private List<ExperimentProduceListGroupVo> getExperimentProduceListGroupVos(List<ExperimentProduce> produces,
			List<ReagentType> reagentTypes, Map<Integer, String> unitMap, boolean distinct) {
		return reagentTypes.stream().map(type -> {
			ExperimentProduceListGroupVo groupVo = new ExperimentProduceListGroupVo();
			List<ExperimentProduceListVo> produceVos = produces.stream()
					.filter(produce -> produce.getReagentTypeId().equals(type.getId())).map(produce -> {
						ExperimentProduceListVo produceVo = new ExperimentProduceListVo();
						produceVo.setId(produce.getId());
						produceVo.setExperimentId(produce.getExperimentId());
						produceVo.setName(produce.getName());
						produceVo.setAmount(produce.getAmount());
						produceVo.setReagentTypeId(produce.getReagentTypeId());
						produceVo.setUnit(unitMap.get(produce.getUnit()));
						return produceVo;
					}).collect(Collectors.toList());
			if (CollectionUtils.isNotEmpty(produceVos)) {
				if (distinct) {
					List<ExperimentProduceListVo> last = new ArrayList<>();
					Set<String> names = produces.stream().map(ExperimentProduce::getName).distinct()
							.collect(Collectors.toSet());
					for (String name : names) {
						for (ExperimentProduceListVo vo : produceVos) {
							if (name != null && name.equals(vo.getName())) {
								last.add(vo);
								break;
							}
						}
					}
					produceVos = last;
				}
				groupVo.setName(type.getName());
				groupVo.setProduceList(produceVos);
				return groupVo;
			}
			return null;
		}).filter(Objects::nonNull).collect(Collectors.toList());
	}

	/**
	 * 关联实验产出列表
	 *
	 * @param experimentId
	 * @param labId
	 * @return
	 */
	public List<ExperimentProduceListGroupVoList> getRelateExperimentProductions(Long experimentId, Long labId) {
		// 校验
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在!");
		Assert.isTrue(experiment.getIsDelete().equals(BoolEnum.FALSE.getValue()), "实验已被删除!");
		Assert.isTrue(experiment.getLabId().equals(labId), "您无法查看其他实验室的试验记录!");

		// experimentRelation
		List<ExperimentRelation> experimentRelations = experimentRelationService.selectList(experimentId);
		List<Long> relateExperiments = experimentRelations.stream().map(ExperimentRelation::getSupId).distinct()
				.collect(Collectors.toList());

		List<Experiment> experiments = experimentService.selectByIds(relateExperiments);
		List<ExperimentProduce> produces = experimentProduceService.selectByExperimentIds(relateExperiments);
		List<Long> typeIds = produces.stream().map(ExperimentProduce::getReagentTypeId).distinct()
				.collect(Collectors.toList());
		List<ReagentType> reagentTypes = reagentTypeService.getSelectedPublicReagentTypeList(typeIds);

		Map<Integer, String> unitMap = dictService.getUnitMap();
		List<ExperimentProduceListGroupVoList> voLists = experiments.stream().map(relateExperiment -> {
			ExperimentProduceListGroupVoList groupVoList = new ExperimentProduceListGroupVoList();
			groupVoList.setExperimentName(relateExperiment.getName());
			List<ExperimentProduce> thisProduces = produces.stream()
					.filter(e -> e.getExperimentId().equals(relateExperiment.getId())).collect(Collectors.toList());
			List<ExperimentProduceListGroupVo> rs = getExperimentProduceListGroupVos(thisProduces, reagentTypes,
					unitMap, true);
			groupVoList.setProduceGroupList(rs);
			return groupVoList;
		}).collect(Collectors.toList());

		return voLists;
	}

	/**
	 * 实验 添加试剂
	 *
	 * @param kitAdd
	 * @param userInfo
	 * @author WuMenghao
	 */
	// TODO 测试
	public void addReagentToExperiment(ExperimentKitAddVo kitAdd, UserInfoVo userInfo) {
		Long labId = userInfo.getLabId();
		Long labMemberId = userInfo.getLabMemberId();
		Experiment experiment = experimentService.selectById(kitAdd.getExperimentId());
		Assert.notNull(experiment, "实验不存在！");
		Assert.isTrue(experiment.getLabId().equals(labId), "实验不属于该实验室！");
		Assert.isTrue(experiment.getExecutorId().equals(labMemberId), "您不是该实验的执行人，无法进行此操作！");

		List<ExperimentKitAddListVo> items = kitAdd.getItems();
		items.forEach(e -> Assert.isTrue(
				e.getAmount() != null && ((e.getKitId() != null && e.getGroupId() != null) || e.getReagentId() != null),
				"请求参数缺失!"));

		List<ExperimentKitAddListVo> kitAdds = items.stream()
				.filter(e -> e.getKitId() != null && e.getGroupId() != null).collect(Collectors.toList());
		List<ExperimentKitAddListVo> reagentAdds = items.stream().filter(e -> e.getReagentId() != null)
				.collect(Collectors.toList());

		List<Long> kitIds = kitAdds.stream().map(ExperimentKitAddListVo::getKitId).distinct()
				.collect(Collectors.toList());
		List<Long> groupIds = kitAdds.stream().map(ExperimentKitAddListVo::getGroupId).distinct()
				.collect(Collectors.toList());
		List<Long> reagentIds = reagentAdds.stream().map(ExperimentKitAddListVo::getReagentId).distinct()
				.collect(Collectors.toList());
		List<ReagentInventory> inventories = reagentInventoryService.selectListByKitIdList(kitIds, groupIds);

		List<Long> ivReagentId = inventories.stream().map(ReagentInventory::getReagentId).distinct()
				.collect(Collectors.toList());
		List<Reagent> reagents = reagentService.selectByReagentIds(reagentIds);
		List<Reagent> ivReagents = reagentService.selectByReagentIds(ivReagentId);

		// kits
		kitIds.addAll(reagents.stream().map(Reagent::getKitId).distinct().collect(Collectors.toList()));
		List<Kit> kits = kitService.selectByIds(kitIds);

		// kitSpec
		List<KitSpec> kitSpecs = kitSpecService.selectList(kitIds);

		// firstReagentTypeMap
		List<Long> reagentTypeIds = reagents.stream().map(Reagent::getReagentTypeId).collect(Collectors.toList());
		reagentTypeIds.addAll(
				inventories.stream().map(ReagentInventory::getReagentTypeId).distinct().collect(Collectors.toList()));
		Map<Long, Long> firstReagentTypeMap = reagentTypeService.selectFirstReagentTypeMap(reagentTypeIds);

		// 有库存
		List<ExperimentBill> experimentBills = inventories.stream().map(e -> {
			// 取用量计算
			ExperimentKitAddListVo addListVo = kitAdds.stream()
					.filter(add -> e.getKitId().equals(add.getKitId()) && e.getGroupId().equals(add.getGroupId()))
					.findFirst().orElse(null);
			if (addListVo != null) {
				KitSpec thisSpec = kitSpecs.stream().filter(kitSpec -> kitSpec.getKitId().equals(e.getKitId())
						&& kitSpec.getReagentId().equals(e.getReagentId())).findFirst().orElse(null);
				if (thisSpec != null) {
					BigDecimal thisSize = addListVo.getAmount()
							.multiply(thisSpec.getSize().divide(thisSpec.getKitSize(), 3, RoundingMode.HALF_UP));
					Reagent reagent = ivReagents.stream().filter(r -> r.getId().equals(e.getReagentId())).findFirst()
							.orElse(null);
					if (reagent != null && reagent.getIsDelete().equals(BoolEnum.FALSE.getValue())) {
						Kit kit = kits.stream().filter(k -> k.getId().equals(e.getKitId())).findFirst().orElse(null);
						if (kit != null && kit.getIsDelete().equals(BoolEnum.FALSE.getValue())) {
							ExperimentBill experimentBill = new ExperimentBill();
							experimentBill.setExperimentId(experiment.getId());
							experimentBill.setSource(ExperimentBillSourceEnum.REAGENT.getSource());
							experimentBill.setSourceId(e.getReagentId());
							experimentBill.setClassify(e.getClassify());
							experimentBill.setName(e.getReagentName());
							String alias = experimentStepContentLogic.getReagentAlias(reagent, kit);
							experimentBill.setAlias(alias);
							experimentBill.setAmount(thisSize);
							experimentBill.setUnit(e.getUnit());
							experimentBill.setInventoryId(e.getId());
							experimentBill.setFirstReagentTypeId(firstReagentTypeMap.get(e.getReagentTypeId()));
							experimentBill.setKitId(kit.getId());
							experimentBill.setKitName(kit.getName());
							if (addListVo.getKitId() != null && addListVo.getGroupId() != null) {
								experimentBill.setType(ExperimentStepReagentTypeEnum.KIT.getValue());
							} else {
								experimentBill.setType(ExperimentStepReagentTypeEnum.REAGENT.getValue());
							}
							return experimentBill;
						}
					}
				}
			}
			return null;
		}).filter(Objects::nonNull).collect(Collectors.toList());

		// 无库存
		experimentBills.addAll(reagents.stream().map(e -> {
			ExperimentKitAddListVo addListVo = reagentAdds.stream().filter(add -> e.getId().equals(add.getReagentId()))
					.findFirst().orElse(null);
			if (addListVo != null) {
				Kit kit = kits.stream().filter(k -> k.getId().equals(e.getKitId())).findFirst().orElse(null);
				if (kit != null && kit.getIsDelete().equals(BoolEnum.FALSE.getValue())) {
					ExperimentBill experimentBill = new ExperimentBill();
					experimentBill.setExperimentId(experiment.getId());
					experimentBill.setSource(ExperimentBillSourceEnum.REAGENT.getSource());
					experimentBill.setSourceId(e.getId());
					experimentBill.setClassify(e.getClassify());
					experimentBill.setName(e.getName());
					String alias = experimentStepContentLogic.getReagentAlias(e, kit);
					experimentBill.setAlias(alias);
					experimentBill.setAmount(addListVo.getAmount());
					experimentBill.setUnit(e.getUnit());
					experimentBill.setFirstReagentTypeId(firstReagentTypeMap.get(e.getReagentTypeId()));
					experimentBill.setKitId(kit.getId());
					experimentBill.setKitName(kit.getName());
					if (addListVo.getKitId() != null && addListVo.getGroupId() != null) {
						experimentBill.setType(ExperimentStepReagentTypeEnum.KIT.getValue());
					} else {
						experimentBill.setType(ExperimentStepReagentTypeEnum.REAGENT.getValue());
					}
					return experimentBill;
				}
			}
			return null;
		}).filter(Objects::nonNull).collect(Collectors.toList()));

		if (experimentBills.size() > 0) {
			experimentBillService.insertBatch(experimentBills);
		}
	}

	/**
	 * 试剂列表 移出试剂
	 *
	 * @param sourceId
	 * @param source
	 * @param experimentId
	 * @param labId
	 * @param labMemberId
	 * @return
	 * @author WuMenghao
	 */
	// TODO 测试
	public void removeExperimentReagent(Long sourceId, Integer source, Long experimentId, Long labId,
			Long labMemberId) {

		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在！");
		Assert.isTrue(experiment.getLabId().equals(labId), "实验不属于该实验室！");
		Assert.isTrue(experiment.getExecutorId().equals(labMemberId), "您不是该实验的执行人，无法进行此操作！");

		// bills
		List<ExperimentBill> bills = experimentBillService.selectBySourceAndExperimentId(sourceId, source,
				experiment.getId());

		// stepReagent
		if (ExperimentBillSourceEnum.REAGENT.getSource().equals(source)) {
			ExperimentStepReagent experimentStepReagent = experimentStepReagentService.selectById(sourceId);
			if (experimentStepReagent != null) {
				List<ExperimentStepReagent> stepReagents = experimentStepReagentService
						.selectByReagentIdAndExperimentId(experimentStepReagent.getReagentId(), experimentId);
				Assert.isTrue(CollectionUtils.isEmpty(stepReagents), "试剂已关联实验步骤，无法直接删除!");
			}
		}

		// 删除bill表
		experimentBillService.deleteBySourceAndExperimentId(sourceId, source, experimentId);

		// 删除多空板中的试剂
		List<Long> billIds = bills.stream().map(ExperimentBill::getId).distinct().collect(Collectors.toList());
		plateGridReagentService.deleteBySourceIdAndType(billIds,
				ExperimentStepMaterialTypeEnum.EXPERIMENT_SAMPLE.getType());

	}

	public List<ExperimentRelationListVo> getRelationList(Long experimentId) {
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在！");
		List<ExperimentRelationListVo> voList = new ArrayList<ExperimentRelationListVo>();
		List<Experiment> list = experimentService.getExperimentList(experiment.getTopicTargetId());
		if (CollectionUtils.isNotEmpty(list)) {
			List<ExperimentRelation> supRelationList = experimentRelationService.selectList(experimentId);
			Map<Long, List<ExperimentRelation>> supMap = supRelationList.stream()
					.collect(Collectors.groupingBy(ExperimentRelation::getSupId));
			DateFormat format = new SimpleDateFormat("MM-dd");
			list.forEach(exp -> {
				if (!exp.getId().equals(experimentId)
						&& !exp.getState().equals(ExperimentStateEnum.NOT_STARTED.getValue())) {
					int produceCount = experimentProduceService.selectProduceCount(exp.getId());
					if (produceCount > 0) {
						ExperimentRelationListVo vo = new ExperimentRelationListVo();
						vo.setExperimentId(exp.getId());
						StringBuilder name = new StringBuilder("实验").append(exp.getSerial()).append("的样品（")
								.append(format.format(exp.getStartTime())).append("）");
						vo.setName(name.toString());
						List<ExperimentRelation> list2 = supMap.get(exp.getId());
						if (CollectionUtils.isNotEmpty(list2)) {
							vo.setIsRelation(BoolEnum.TRUE.getValue());
						}
						voList.add(vo);
					}
				}
			});
		}
		return voList;
	}

	private void deleteRelation(Long experimentId, List<Long> supRelationIds) {
		if (CollectionUtils.isNotEmpty(supRelationIds)) {
			List<ExperimentProduce> produceList = experimentProduceService.selectByExperimentIds(supRelationIds);
			if (CollectionUtils.isNotEmpty(produceList)) {
				List<Long> sourceIds = produceList.stream().map(ExperimentProduce::getId).distinct()
						.collect(Collectors.toList());
				experimentBillService.delete(experimentId, ExperimentBillSourceEnum.EXPERIMENT_PRODUCT.getSource(),
						sourceIds);
			}
			experimentRelationService.delete(experimentId, supRelationIds);
		}
	}

	public void experimentRelation(ExperimentRelationVo relationVo) {

		if (CollectionUtils.isEmpty(relationVo.getRelationIds())) {
			List<ExperimentRelation> supRelationList = experimentRelationService
					.selectList(relationVo.getExperimentId());
			if (CollectionUtils.isNotEmpty(supRelationList)) {
				List<Long> supRelationIds = supRelationList.stream().map(ExperimentRelation::getSupId).distinct()
						.collect(Collectors.toList());
				this.deleteRelation(relationVo.getExperimentId(), supRelationIds);
			}

		} else {
			List<Long> supRelationIds = new ArrayList<Long>();
			List<ExperimentRelation> supRelationList = experimentRelationService
					.selectList(relationVo.getExperimentId());
			supRelationList.forEach(relation -> {
				int i = relationVo.getRelationIds().indexOf(relation.getSupId());
				if (i == -1) {
					supRelationIds.add(relation.getSupId());
				}
			});
			if (CollectionUtils.isNotEmpty(supRelationIds)) {
				this.deleteRelation(relationVo.getExperimentId(), supRelationIds);
			}

			Map<Long, List<ExperimentRelation>> supMap = supRelationList.stream()
					.collect(Collectors.groupingBy(ExperimentRelation::getSupId));
			List<Experiment> relationList = experimentService.selectByIds(relationVo.getRelationIds());
			List<ExperimentRelation> relList = new ArrayList<ExperimentRelation>();
			relationList.forEach(sup -> {
				List<ExperimentRelation> list = supMap.get(sup.getId());
				if (CollectionUtils.isEmpty(list)) {
					ExperimentRelation relation = new ExperimentRelation();
					relation.setExperimentId(relationVo.getExperimentId());
					relation.setSupId(sup.getId());
					relation.setSupSerial(sup.getSerial());
					relation.setSupTime(sup.getStartTime());
					relList.add(relation);
				}
			});
			experimentRelationService.insertBatch(relList);

			List<ExperimentProduce> produceList = experimentProduceService
					.selectByExperimentIds(relationVo.getRelationIds());
			if (CollectionUtils.isNotEmpty(produceList)) {
				List<ExperimentBill> biList = experimentBillService.selectBillList(relationVo.getExperimentId(),
						ExperimentBillSourceEnum.EXPERIMENT_PRODUCT.getSource());
				Map<Long, List<ExperimentBill>> billMap = biList.stream()
						.collect(Collectors.groupingBy(ExperimentBill::getSourceId));
				List<ExperimentBill> billList = new ArrayList<>();

				produceList.forEach(produce -> {
					List<ExperimentBill> list = billMap.get(produce.getId());
					if (CollectionUtils.isEmpty(list)) {
						ExperimentBill bill = new ExperimentBill();
						bill.setExperimentId(relationVo.getExperimentId());
						bill.setName(produce.getName());
						bill.setClassify(Classify.SAMPLE.getValue());
						bill.setSource(ExperimentBillSourceEnum.EXPERIMENT_PRODUCT.getSource());
						bill.setSourceId(produce.getId());
						bill.setAmount(produce.getAmount() != null ? produce.getAmount() : BigDecimal.ZERO);
						bill.setAlias(produce.getAlias());
						bill.setUnit(produce.getUnit());
						bill.setReagentTypeId(produce.getReagentTypeId());
						bill.setFirstReagentTypeId(produce.getReagentTypeId());
						billList.add(bill);
					}
				});
				experimentBillService.insertBatch(billList);
			}

		}
	}

//	public void experimentInfoSave(Long topicExperimentId, UserInfoVo userInfo) {
//		TopicExperiment topicExperiment = topicExperimentService.selectById(topicExperimentId);
//		if (topicExperiment.getMethodId() == null) {
//			return;
//		}
//		experimentInfoSave(topicExperiment.getExperimentId());
//	}

	/**
	 * 重复实验
	 * 
	 * @param topicExperiment
	 */
	public Experiment repeatExperiment(TopicExperiment topicExperiment) {
		Long lastExperimentId = topicExperiment.getExperimentId();
		Experiment experiment = experimentService.experimentAdd(topicExperiment);

		List<ExperimentBill> addBillList = new ArrayList<>();
		List<ExperimentStepReagent> addStepReagentList = new ArrayList<>();
		List<ExperimentStepTimer> addTimersList = new ArrayList<>();
		List<ExperimentStepText> addTextList = new ArrayList<>();

		List<ExperimentBill> billList = experimentBillService.selectList(lastExperimentId);
		List<ExperimentPhase> phaseList = experimentPhaseService.selectList(lastExperimentId);
		if (CollUtil.isNotEmpty(phaseList)) {
			List<ExperimentStep> stepList = experimentStepService.getExperimentStepList(lastExperimentId);
			Map<Long, List<ExperimentStep>> stepMap = stepList.stream()
					.collect(Collectors.groupingBy(ExperimentStep::getExperimentPhaseId));

			List<ExperimentStepReagent> stepReagentList = experimentStepReagentService
					.selectStepReagentList(lastExperimentId);
			List<ExperimentStepTimer> timerList = experimentStepTimerService.selectStepTimerList(lastExperimentId);
			List<ExperimentStepText> textList = experimentStepTextService.selectList(lastExperimentId);

			for (ExperimentPhase phase : phaseList) {
				ExperimentPhase experimentPhase = new ExperimentPhase();
				experimentPhase.setExperimentId(experiment.getId());
				experimentPhase.setMethodPhaseId(phase.getMethodPhaseId());
				experimentPhase.setName(phase.getName());
				experimentPhase.setDescription(phase.getDescription());
				experimentPhase.setSort(phase.getSort());
				experimentPhase = experimentPhaseService.insert(experimentPhase);
				List<ExperimentStep> stepSuList = stepMap.get(phase.getId());
				for (ExperimentStep step : stepSuList) {
					ExperimentStep experimentStep = new ExperimentStep();
					experimentStep.setExperimentId(experiment.getId());
					experimentStep.setExperimentPhaseId(experimentPhase.getId());
					experimentStep.setMethodStepId(step.getMethodStepId());
					experimentStep.setSort(step.getSort());
					experimentStep.setContent(step.getContent());
					experimentStep.setState(ExperimentStateEnum.NOT_STARTED.getValue());
					experimentStep = experimentStepService.insert(experimentStep);
					if (CollUtil.isNotEmpty(billList)) {
						for (Iterator<ExperimentBill> iterator = billList.iterator(); iterator.hasNext();) {
							ExperimentBill bill = iterator.next();
							if (step.getId().equals(bill.getStepId())) {
								ExperimentBill experimentBill = MyBeanUtils.copyBean(bill, ExperimentBill.class);
								experimentBill.setId(null);
								experimentBill.setExperimentId(experiment.getId());
								experimentBill.setPhaseId(experimentPhase.getId());
								experimentBill.setStepId(experimentStep.getId());
								addBillList.add(experimentBill);
								iterator.remove();
							}
						}
					}
					if (CollUtil.isNotEmpty(stepReagentList)) {
						for (Iterator<ExperimentStepReagent> iterator = stepReagentList.iterator(); iterator
								.hasNext();) {
							ExperimentStepReagent stepReagent = iterator.next();
							if (step.getId().equals(stepReagent.getStepId())) {
								ExperimentStepReagent experimentStepReagent = MyBeanUtils.copyBean(stepReagent,
										ExperimentStepReagent.class);
								experimentStepReagent.setId(null);
								experimentStepReagent.setExperimentId(experiment.getId());
								experimentStepReagent.setPhaseId(experimentPhase.getId());
								experimentStepReagent.setStepId(experimentStep.getId());
								addStepReagentList.add(experimentStepReagent);
								iterator.remove();
							}
						}
					}
					if (CollUtil.isNotEmpty(timerList)) {
						for (Iterator<ExperimentStepTimer> iterator = timerList.iterator(); iterator.hasNext();) {
							ExperimentStepTimer timer = iterator.next();
							if (step.getId().equals(timer.getStepId())) {
								ExperimentStepTimer stepTimer = new ExperimentStepTimer();
								stepTimer.setExperimentId(experiment.getId());
								stepTimer.setPhaseId(experimentPhase.getId());
								stepTimer.setStepId(experimentStep.getId());
								stepTimer.setTime(timer.getTime());
								stepTimer.setRemainTime(timer.getTime());
								addTimersList.add(stepTimer);
								iterator.remove();
							}
						}
					}

					if (CollUtil.isNotEmpty(textList)) {
						for (Iterator<ExperimentStepText> iterator = textList.iterator(); iterator.hasNext();) {
							ExperimentStepText text = iterator.next();
							if (step.getId().equals(text.getStepId())) {
								ExperimentStepText stepText = new ExperimentStepText();
								stepText.setExperimentId(experiment.getId());
								stepText.setPhaseId(experimentPhase.getId());
								stepText.setStepId(experimentStep.getId());
								stepText.setContent(text.getContent());
								stepText.setType(text.getType());
								stepText.setGroupType(text.getGroupType());
								addTextList.add(stepText);
								iterator.remove();
							}
						}
					}

				}
			}

			if (CollUtil.isNotEmpty(stepReagentList)) {
				for (ExperimentStepReagent stepReagent : stepReagentList) {
					ExperimentStepReagent experimentStepReagent = MyBeanUtils.copyBean(stepReagent,
							ExperimentStepReagent.class);
					experimentStepReagent.setId(null);
					experimentStepReagent.setExperimentId(experiment.getId());
					addStepReagentList.add(experimentStepReagent);
				}
			}
			if (CollUtil.isNotEmpty(timerList)) {
				for (ExperimentStepTimer timer : timerList) {
					ExperimentStepTimer stepTimer = new ExperimentStepTimer();
					stepTimer.setExperimentId(experiment.getId());
					stepTimer.setTime(timer.getTime());
					stepTimer.setRemainTime(timer.getTime());
					addTimersList.add(stepTimer);
				}
			}

			if (CollUtil.isNotEmpty(textList)) {
				for (ExperimentStepText text : textList) {
					ExperimentStepText stepText = new ExperimentStepText();
					stepText.setExperimentId(experiment.getId());
					stepText.setContent(text.getContent());
					stepText.setType(text.getType());
					stepText.setGroupType(text.getGroupType());
					addTextList.add(stepText);
				}
			}
		}

		if (CollUtil.isNotEmpty(billList)) {
			for (ExperimentBill bill : billList) {
				ExperimentBill experimentBill = MyBeanUtils.copyBean(bill, ExperimentBill.class);
				experimentBill.setId(null);
				experimentBill.setExperimentId(experiment.getId());
				addBillList.add(experimentBill);
			}
		}

		List<ExperimentGroup> groupList = experimentGroupService.selectList(lastExperimentId);
		if (CollUtil.isNotEmpty(groupList)) {
			for (ExperimentGroup group : groupList) {
				group.setId(null);
				group.setExperimentId(experiment.getId());
			}
			experimentGroupService.insertByBatch(groupList);
		}
		List<ExperimentGroupRelation> groupRelationList = experimentGroupRelationService.selectList(lastExperimentId);
		if (CollUtil.isNotEmpty(groupRelationList)) {
			Map<Long, List<ExperimentGroupRelation>> relationMap = groupRelationList.stream()
					.collect(Collectors.groupingBy(ExperimentGroupRelation::getParentId));
			List<ExperimentGroupRelation> suList1 = relationMap.get(0L);
			for (ExperimentGroupRelation relation1 : suList1) {
				List<ExperimentGroupRelation> suList2 = relationMap.get(relation1.getId());
				relation1.setId(null);
				relation1.setExperimentId(experiment.getId());
				relation1 = experimentGroupRelationService.insert(relation1);
				if (CollUtil.isNotEmpty(suList2)) {
					for (ExperimentGroupRelation relation2 : suList2) {
						List<ExperimentGroupRelation> suList3 = relationMap.get(relation2.getId());
						relation2.setId(null);
						relation2.setParentId(relation1.getId());
						relation2.setExperimentId(experiment.getId());
						relation2 = experimentGroupRelationService.insert(relation2);
						if (CollUtil.isNotEmpty(suList3)) {
							for (ExperimentGroupRelation relation3 : suList3) {
								relation3.setId(null);
								relation3.setParentId(relation2.getId());
								relation3.setExperimentId(experiment.getId());
								experimentGroupRelationService.insert(relation3);
							}
						}
					}
				}
			}
		}

		if (CollUtil.isNotEmpty(addBillList)) {
			experimentBillService.insertBatch(addBillList);
		}
		if (CollUtil.isNotEmpty(addStepReagentList)) {
			experimentStepReagentService.insertBatch(addStepReagentList);
		}
		if (CollUtil.isNotEmpty(addTimersList)) {
			experimentStepTimerService.insertBatch(addTimersList);
		}
		if (CollUtil.isNotEmpty(addTextList)) {
			experimentStepTextService.insertBatch(addTextList);
		}

		return experiment;
	}

	/**
	 * 保存实验内容信息
	 *
	 * @param experimentId
	 */
	public void experimentInfoSave(Long experimentId) {

		Experiment experiment = experimentService.selectById(experimentId);
		if (experiment.getMethodId() == null || BoolEnum.TRUE.getValue().equals(experiment.getIsImport())) {
			return;
		}

		int count = experimentPhaseService.selectCount(experimentId);
		if (count > 0) {
			return;
		}

		MethodDetail methodDetail = methodLogic.getMethodDetail(experiment.getMethodId(), BoolEnum.FALSE,
				experiment.getLabId());
		Assert.notNull(methodDetail, "方法不存在！");

		List<MethodPhaseDetail> phaseList = methodDetail.getPhaseList();
		if (!CollectionUtils.isEmpty(phaseList)) {
			for (MethodPhaseDetail phase : phaseList) {
				ExperimentPhase experimentPhase = new ExperimentPhase();
				experimentPhase.setExperimentId(experiment.getId());
				experimentPhase.setMethodPhaseId(phase.getId());
				experimentPhase.setName(phase.getName());
				experimentPhase.setDescription(phase.getTip());
				experimentPhase.setSort(phase.getSort());
				experimentPhase = experimentPhaseService.insert(experimentPhase);
				List<MethodStepDetail> stepList = phase.getStepList();
				if (!CollectionUtils.isEmpty(stepList)) {
					for (MethodStepDetail step : stepList) {
						ExperimentStep experimentStep = new ExperimentStep();
						experimentStep.setExperimentId(experiment.getId());
						experimentStep.setExperimentPhaseId(experimentPhase.getId());
						experimentStep.setMethodStepId(step.getId());
						experimentStep.setSort(step.getSort());
						experimentStep.setContent(step.getContent());
						experimentStep.setState(ExperimentStateEnum.NOT_STARTED.getValue());
						experimentStep = experimentStepService.insert(experimentStep);
						List<MethodRelateReagent> reagentList = methodRelateReagentService.listByStepId(step.getId());
						if (!CollectionUtils.isEmpty(reagentList)) {
							this.saveMethodReagent(reagentList, experimentStep, experimentPhase);
						}
						List<MethodRelateTimer> timerVoList = step.getTimerList();
						if (!CollectionUtils.isEmpty(timerVoList)) {
							this.saveMethodTimer(timerVoList, experimentStep);
						}

					}
				}
			}
		}

		experiment.setDescription(methodDetail.getDescription());
		experiment.setIsImport(BoolEnum.TRUE.getValue());
		experimentService.updateById(experiment);
	}

	private void saveMethodTimer(List<MethodRelateTimer> timerVoList, ExperimentStep experimentStep) {
		if (CollectionUtils.isEmpty(timerVoList)) {
			return;
		}
		List<ExperimentStepTimer> stepTimersList = new ArrayList<>();
		for (MethodRelateTimer timerVo : timerVoList) {
			ExperimentStepTimer timer = new ExperimentStepTimer();
			timer.setExperimentId(experimentStep.getExperimentId());
			timer.setPhaseId(experimentStep.getExperimentPhaseId());
			timer.setStepId(experimentStep.getId());
			timer.setTime(timerVo.getTime());
			timer.setRemainTime(timerVo.getTime());
			stepTimersList.add(timer);
		}
		if (!CollectionUtils.isEmpty(stepTimersList)) {
			experimentStepTimerService.insertBatch(stepTimersList);
		}

	}

	private void saveMethodReagent(List<MethodRelateReagent> reagentList, ExperimentStep experimentStep,
			ExperimentPhase experimentPhase) {
		if (CollectionUtils.isEmpty(reagentList)) {
			return;
		}

		Map<Integer, String> unitMap = dictService.getUnitMap();

		List<Long> reagentIds = reagentList.stream().map(MethodRelateReagent::getReagentId)
				.collect(Collectors.toList());
		List<Reagent> reagents = reagentService.selectByReagentIds(reagentIds);
		Map<Long, List<Reagent>> reagentMap = reagents.stream().collect(Collectors.groupingBy(Reagent::getId));

		List<Long> kitIds = reagents.stream().map(Reagent::getKitId).distinct().collect(Collectors.toList());
		List<Kit> kits = kitService.selectByIds(kitIds);
		Map<Long, List<Kit>> kitMap = kits.stream().collect(Collectors.groupingBy(Kit::getId));

		List<Long> reagentTypeIds = reagents.stream().map(Reagent::getReagentTypeId).collect(Collectors.toList());
		Map<Long, Long> firstReagentTypeMap = reagentTypeService.selectFirstReagentTypeMap(reagentTypeIds);

		List<ExperimentStepReagent> stepReagentList = new ArrayList<>();
		List<ExperimentBill> billList = new ArrayList<>();
		for (MethodRelateReagent reagentVo : reagentList) {
			List<Reagent> listReagent = reagentMap.get(reagentVo.getReagentId());
			if (!CollectionUtils.isEmpty(listReagent)) {
				Reagent reagent = listReagent.get(0);
				Kit kit = kitMap.get(reagent.getKitId()).get(0);

				ExperimentStepReagent stepReagent = new ExperimentStepReagent();
				stepReagent.setExperimentId(experimentStep.getExperimentId());
				stepReagent.setPhaseId(experimentStep.getExperimentPhaseId());
				stepReagent.setStepId(experimentStep.getId());
				stepReagent.setUuid(reagentVo.getUuid());
				stepReagent.setReagentId(reagentVo.getReagentId());
				stepReagent.setName(reagentVo.getReagentName());
				stepReagent.setAmount(reagentVo.getAmount() != null ? reagentVo.getAmount() : BigDecimal.ZERO);

				stepReagent.setGroupId(kit.getKitGroup());
				stepReagent.setClassify(kit.getClassify());
				stepReagent.setAlias(reagent.getAlias());
				stepReagent.setType(reagentVo.getType());

				stepReagent.setUnit(unitMap.get(reagent.getUnit()));
				stepReagent.setFirstReagentTypeId(firstReagentTypeMap.get(reagent.getReagentTypeId()));

				stepReagentList.add(stepReagent);

				ExperimentBill experimentBill = new ExperimentBill();
				experimentBill.setExperimentId(experimentStep.getExperimentId());
				experimentBill.setPhaseId(experimentPhase.getId());
				experimentBill.setPhaseSort(experimentPhase.getSort());
				experimentBill.setStepId(experimentStep.getId());
				experimentBill.setStepSort(experimentStep.getSort());
				experimentBill.setSource(ExperimentBillSourceEnum.REAGENT.getSource());
				experimentBill.setSourceId(reagentVo.getReagentId());

				experimentBill.setClassify(kit.getClassify());
				experimentBill.setName(reagentVo.getReagentName());
				experimentBill.setAlias(reagent.getAlias());
				experimentBill.setAmount(reagentVo.getAmount() != null ? reagentVo.getAmount() : BigDecimal.ZERO);
				experimentBill.setUnit(reagent.getUnit());
				experimentBill.setFirstReagentTypeId(firstReagentTypeMap.get(reagent.getReagentTypeId()));
				experimentBill.setIsMethod(BoolEnum.TRUE.getValue());
				billList.add(experimentBill);
			}
		}
		if (!CollectionUtils.isEmpty(stepReagentList)) {
			experimentStepReagentService.insertBatch(stepReagentList);
			experimentBillService.insertBatch(billList);
		}

	}

	/**
	 * 结束实验
	 */
	public Long experimentEnd(UserInfoVo userInfo, Long experimentId, int isSaveMethod, Integer isExpect) {
		Experiment experiment = experimentService.selectById(experimentId);
		experimentService.endExperiment(experiment.getId(), isExpect);

		List<ExperimentStep> stepList = experimentStepService.getExperimentStepList(experimentId);
		if (!CollectionUtils.isEmpty(stepList)) {
			stepList.forEach(step -> {
				if (!step.getState().equals(ExperimentStateEnum.COMPLETE.getValue())) {
					step.setState(ExperimentStateEnum.COMPLETE.getValue());
					experimentStepService.updateById(step);
				}
			});
		}
		Long methodId = null;
		if (isSaveMethod == 1) {// 保存新方法
			methodId = experimentToMethod(userInfo, experiment);
			if (methodId != null) {
				experiment.setMethodId(methodId);
				experimentService.updateById(experiment);

				TopicExperiment topicExperiment = new TopicExperiment();
				topicExperiment.setId(experiment.getTopicExperimentId());
				topicExperiment.setMethodId(methodId);
				topicExperimentService.updateById(topicExperiment);
			}
		}
		// 新增取用记录
		this.addInventoryRecord(userInfo, experimentId);
		return methodId;
	}

	// 新增取用记录
	private void addInventoryRecord(UserInfoVo userInfo, Long experimentId) {
		List<ExperimentBill> experimentBills = experimentBillService.selectBillList(experimentId,
				ExperimentBillSourceEnum.REAGENT.getSource());
		if (CollectionUtils.isNotEmpty(experimentBills)) {
			List<Long> usedKitIds = experimentBills.stream().map(ExperimentBill::getKitId).distinct()
					.collect(Collectors.toList());
			if (usedKitIds.size() > 0) {
				inventoryRecordService.add(userInfo, usedKitIds, InventoryRecordEnum.TAKE);
			}
		}
	}

	/**
	 * 是否是对应实验执行人的组长
	 *
	 * @param experimentId
	 * @param userInfo
	 * @return
	 */
	public boolean isLeader(Long experimentId, UserInfoVo userInfo) {
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在");
		TeamMemberVo leader = teamLogic.getLeaderOfTeamMember(experiment.getLabId(), experiment.getExecutorId());
		if (leader != null && leader.getLabMemberId().equals(experiment.getExecutorId())) {// 组长是主执行人
			if (userInfo.getIsOwner()) {
				return true;
			}
			return false;
		}
		if (leader != null && leader.getLabMemberId().equals(userInfo.getLabMemberId())) {
			return true;
		}

		if (leader == null && userInfo.getIsOwner()) {
			return true;
		}
		return false;
	}


	

	/**
	 * 获取当前用户的参与实验列表
	 *
	 * @param userVo
	 * @return
	 */
	public List<Long> getExperimentIdList(UserInfoVo userVo) {
		List<Integer> stateList = new ArrayList<>();
		stateList.add(1);
		stateList.add(2);
		List<Experiment> experimentList = experimentService.getExperimentByConditionList(userVo.getLabMemberId(),
				stateList);
		List<Long> experimentIdList = experimentList.stream().map(Experiment::getId).collect(Collectors.toList());

		return experimentIdList;
	}

	
	/**
	 * @Description: 删除实验分组关系列表
	 * @Param [id]
	 */
	public void deleteExperimentGroup(ExperimentGroupRelationIdVo vo, Long labId) {
		this.checkExperiment(vo.getExperimentId(), labId);
		ExperimentGroupRelation relation = experimentGroupRelationService.selectById(vo.getId());
		Assert.isTrue(relation != null, "实验分组不存在！");
		List<Long> delIds = new ArrayList<>();
		delIds.add(relation.getId());
		findChildId(delIds, Arrays.asList(relation.getId()));
		experimentGroupRelationService.deleteBatch(delIds);
	}

	/**
	 * @Description: 查询子节点id并添加
	 * @Param [result, parentIds]
	 */
	private void findChildId(List<Long> result, List<Long> parentIds) {
		List<Long> childIdList = experimentGroupRelationService.selectByParentId(parentIds).stream()
				.map(ExperimentGroupRelation::getId).collect(Collectors.toList());
		if (!CollectionUtils.isEmpty(childIdList)) {
			result.addAll(childIdList);
			findChildId(result, childIdList);
		}
	}

	public Map<String, List<ExperimentGroup>> getExperimentGroupDetail(Long experimentId, UserInfoVo userInfoVo) {
		checkExperiment(experimentId, userInfoVo.getLabId());
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验不存在!");
		this.experimentInfoSave(experiment.getId());
		Map<String, List<ExperimentGroup>> result = experimentGroupService.selectList(experimentId).stream()
				.collect(Collectors.groupingBy(e -> ExperimentGroupEnum.getKey(e.getType())));
		return result;
	}

	/**
	 * @Description: 获取实验列表
	 * @Param [experimentId, userInfoVo]
	 */
	public List<ExperimentGroup> getExperimentGroupList(Long experimentId, UserInfoVo userInfoVo) {
		List<ExperimentGroupRelationTreeVo> treeVos = this.getExperimentGroupTree(experimentId, userInfoVo);
		List<ExperimentGroup> result = build(experimentId, treeVos, "", 0);
		return result;
	}

	public List<ExperimentGroup> build(Long experimentId, List<ExperimentGroupRelationTreeVo> treeVos, String content,
			Integer sort) {
		List<ExperimentGroup> result = new ArrayList<>();
		for (ExperimentGroupRelationTreeVo f : treeVos) {
			List<ExperimentGroupRelationTreeVo> sencod = f.getChild();
			String contentStr = content + f.getContent();
			if (CollectionUtils.isNotEmpty(sencod)) {
				List<ExperimentGroup> temp = build(experimentId, sencod, contentStr, sort);
				result.addAll(temp);
				sort = sort + temp.size();
			} else {
				sort++;
				ExperimentGroup group = new ExperimentGroup();
				group.setId(f.getId());
				group.setSort(sort);
				group.setExperimentId(experimentId);
				group.setContent(contentStr);
				result.add(group);
			}
		}
		return result;
	}


	public ExperimentProcessVo getExperimentProcess(Long experimentId, UserInfoVo userInfo) {
		ExperimentProcessVo dtailsVo = new ExperimentProcessVo();
		Experiment experiment = experimentService.selectById(experimentId);
		Assert.notNull(experiment, "实验信息不存在");

		List<ExperimentPhaseProcessVo> phaseList = experimentPhaseService.getExperimentPhaseVoOfProcess(experimentId);
		dtailsVo.setPhaseList(phaseList);

		if (!CollectionUtils.isEmpty(phaseList)) {
			phaseFor: for (ExperimentPhaseProcessVo phase : phaseList) {
				if (ExperimentStateEnum.NOT_STARTED.getValue().equals(phase.getState())
						|| ExperimentStateEnum.UNDER_WAY.getValue().equals(phase.getState())) {
					List<ExperimentStepProcessVo> stepList = phase.getExperimentStepVoList();
					if (!CollectionUtils.isEmpty(stepList)) {
						for (ExperimentStepProcessVo step : stepList) {
							if (ExperimentStateEnum.NOT_STARTED.getValue().equals(step.getState())
									|| ExperimentStateEnum.UNDER_WAY.getValue().equals(step.getState())) {
								dtailsVo.setUnderWayPhaseId(phase.getPhaseId());
								dtailsVo.setUnderWayStepId(step.getStepId());
								break phaseFor;
							}
						}
					}
				}
			}
		}
		return dtailsVo;
	}
}
